- Timestamp:
- Dec 16, 2005, 5:18:39 PM (21 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/pap_branch_051214/psModules/src/imsubtract/pmSubtractBias.c
r5552 r5795 1 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2 // XXX WARNING: I have completely replaced this file with an OLD VERSION (that works) instead of the 3 // one that was being worked on. 4 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 5 1 6 /** @file pmSubtractBias.c 2 7 * … … 6 11 * @author GLG, MHPCC 7 12 * 8 * @version $Revision: 1.6 $ $Name: not supported by cvs2svn $9 * @date $Date: 2005-1 1-19 00:55:18$13 * @version $Revision: 1.6.8.1 $ $Name: not supported by cvs2svn $ 14 * @date $Date: 2005-12-17 03:18:39 $ 10 15 * 11 16 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii 12 17 * 13 18 */ 14 /*****************************************************************************/ 15 /* INCLUDE FILES */ 16 /*****************************************************************************/ 17 #include <stdio.h> 18 #include <math.h> 19 #include <string.h> 20 #include "pslib.h" 19 21 20 #if HAVE_CONFIG_H 22 21 #include <config.h> 23 22 #endif 23 24 24 #include "pmSubtractBias.h" 25 25 26 /*****************************************************************************/ 27 /* DEFINE STATEMENTS */ 28 /*****************************************************************************/ 26 #define PM_SUBTRACT_BIAS_POLYNOMIAL_ORDER 2 27 #define PM_SUBTRACT_BIAS_SPLINE_ORDER 3 28 29 29 // XXX: put these in psConstants.h 30 void PS_POLY1D_PRINT( 31 psPolynomial1D *poly) 30 void PS_POLY1D_PRINT(psPolynomial1D *poly) 32 31 { 33 32 printf("-------------- PS_POLY1D_PRINT() --------------\n"); … … 57 56 }\ 58 57 59 /*****************************************************************************/60 /* TYPE DEFINITIONS */61 /*****************************************************************************/62 63 /*****************************************************************************/64 /* GLOBAL VARIABLES */65 /*****************************************************************************/66 psS32 currentId = 0; // XXX: remove67 psS32 memLeaks = 0; // XXX: remove68 //PRINT_MEMLEAKS(8); XXX69 /*****************************************************************************/70 /* FILE STATIC VARIABLES */71 /*****************************************************************************/72 73 /*****************************************************************************/74 /* FUNCTION IMPLEMENTATION - LOCAL */75 /*****************************************************************************/76 77 58 /****************************************************************************** 78 psSubtractFrame(): this routine will take as input the pmReadout for the input 79 image and a pmReadout for the bias image. The bias image is subtracted in 80 place from the input image. We assume that sizes and types are checked 81 elsewhere. 82 83 XXX: Verify that the image and readout offsets are being used the right way. 84 85 XXX: Ensure that it does the correct thing with image size. 59 psSubtractFrame(): this routine will take as input a readout for the input 60 image and a readout for the bias image. The bias image is subtracted in 61 place from the input image. 86 62 *****************************************************************************/ 87 static pmReadout *SubtractFrame( 88 pmReadout *in, 89 const pmReadout *bias) 63 static pmReadout *SubtractFrame(pmReadout *in, 64 const pmReadout *bias) 90 65 { 91 // XXX: When did the ->row0 and ->col0 offsets get coded? 92 for (psS32 i=0;i<in->image->numRows;i++) { 93 for (psS32 j=0;j<in->image->numCols;j++) { 66 psS32 i; 67 psS32 j; 68 69 if (bias == NULL) { 70 psLogMsg(__func__, PS_LOG_WARN, 71 "WARNING: pmSubtractBias.c: SubtractFrame(): bias frame is NULL. Returning original image.\n"); 72 return(in); 73 } 74 75 76 if ((in->image->numRows + in->row0 - bias->row0) > bias->image->numRows) { 77 psError(PS_ERR_UNKNOWN,true, "bias image does not have enough rows. Returning in image\n"); 78 return(in); 79 } 80 if ((in->image->numCols + in->col0 - bias->col0) > bias->image->numCols) { 81 psError(PS_ERR_UNKNOWN,true, "bias image does not have enough columns. Returning in image\n"); 82 return(in); 83 } 84 85 for (i=0;i<in->image->numRows;i++) { 86 for (j=0;j<in->image->numCols;j++) { 94 87 in->image->data.F32[i][j]-= 95 88 bias->image->data.F32[i+in->row0-bias->row0][j+in->col0-bias->col0]; 96 97 89 if ((in->mask != NULL) && (bias->mask != NULL)) { 98 90 (in->mask->data.U8[i][j])|= … … 105 97 } 106 98 107 108 /******************************************************************************109 psSubtractDarkFrame(): this routine will take as input the pmReadout for the110 input image and a pmReadout for the dark image. The dark image is scaled and111 subtracted in place from the input image.112 113 XXX: Verify that the image and readout offsets are being used the right way.114 115 XXX: Ensure that it does the correct thing with image size.116 *****************************************************************************/117 static pmReadout *SubtractDarkFrame(118 pmReadout *in,119 const pmReadout *dark,120 psF32 scale)121 {122 // XXX: When did the ->row0 and ->col0 offsets get coded?123 if (fabs(scale) > FLT_EPSILON) {124 for (psS32 i=0;i<in->image->numRows;i++) {125 for (psS32 j=0;j<in->image->numCols;j++) {126 in->image->data.F32[i][j]-=127 (scale * dark->image->data.F32[i+in->row0-dark->row0][j+in->col0-dark->col0]);128 129 if ((in->mask != NULL) && (dark->mask != NULL)) {130 (in->mask->data.U8[i][j])|=131 dark->mask->data.U8[i+in->row0-dark->row0][j+in->col0-dark->col0];132 }133 }134 }135 } else {136 for (psS32 i=0;i<in->image->numRows;i++) {137 for (psS32 j=0;j<in->image->numCols;j++) {138 in->image->data.F32[i][j]-=139 dark->image->data.F32[i+in->row0-dark->row0][j+in->col0-dark->col0];140 141 if ((in->mask != NULL) && (dark->mask != NULL)) {142 (in->mask->data.U8[i][j])|=143 dark->mask->data.U8[i+in->row0-dark->row0][j+in->col0-dark->col0];144 }145 }146 }147 }148 149 return(in);150 }151 152 99 /****************************************************************************** 153 100 ImageSubtractScalar(): subtract a scalar from the input image. 154 101 155 XXX: Is there a psLib function for this? 102 XXX: Use a psLib function for this. 103 104 XXX: This should 156 105 *****************************************************************************/ 157 static psImage *ImageSubtractScalar( 158 psImage *image, 159 psF32 scalar) 106 static psImage *ImageSubtractScalar(psImage *image, 107 psF32 scalar) 160 108 { 161 109 for (psS32 i=0;i<image->numRows;i++) { … … 221 169 222 170 if (numOptions == 0) { 223 psError(PS_ERR_UNKNOWN,true, "No allowablestatistics options have been specified.\n");171 psError(PS_ERR_UNKNOWN,true, "No statistics options have been specified.\n"); 224 172 } 225 173 if (numOptions != 1) { … … 230 178 } 231 179 232 /****************************************************************************** 233 Polynomial1DCopy(): This private function copies the members of the existing 234 psPolynomial1D "in" into the existing psPolynomial1D "out". The previous 235 members of the existing psPolynomial1D "out" are psFree'ed. 236 *****************************************************************************/ 237 static psBool Polynomial1DCopy( 238 psPolynomial1D *out, 239 psPolynomial1D *in) 240 { 241 psFree(out->coeff); 242 psFree(out->coeffErr); 243 psFree(out->mask); 244 245 out->type = in->type; 246 out->nX = in->nX; 247 248 out->coeff = (psF64 *) psAlloc((in->nX + 1) * sizeof(psF64)); 249 // XXX: use memcpy 250 for (psS32 i = 0 ; i < (in->nX + 1) ; i++) { 251 out->coeff[i] = in->coeff[i]; 252 } 253 254 out->coeffErr = (psF64 *) psAlloc((in->nX + 1) * sizeof(psF64)); 255 // XXX: use memcpy 256 for (psS32 i = 0 ; i < (in->nX + 1) ; i++) { 257 out->coeffErr[i] = in->coeffErr[i]; 258 } 259 260 out->mask = (psMaskType *) psAlloc((in->nX + 1) * sizeof(psMaskType)); 261 // XXX: use memcpy 262 for (psS32 i = 0 ; i < (in->nX + 1) ; i++) { 263 out->mask[i] = in->mask[i]; 264 } 265 266 return(true); 267 } 268 269 /****************************************************************************** 270 Polynomial1DDup(): This private function duplicates and then returns the input 271 psPolynomial1D "in". 272 *****************************************************************************/ 273 static psPolynomial1D *Polynomial1DDup( 274 psPolynomial1D *in) 275 { 276 psPolynomial1D *out = psPolynomial1DAlloc(in->nX, in->type); 277 Polynomial1DCopy(out, in); 278 return(out); 279 } 280 281 282 /****************************************************************************** 283 SplineCopy(): This private function copies the members of the existing 284 psSpline in into the existing psSpline out. 285 *****************************************************************************/ 286 static psBool SplineCopy( 287 psSpline1D *out, 288 psSpline1D *in) 289 { 290 PS_ASSERT_PTR_NON_NULL(out, false); 291 PS_ASSERT_PTR_NON_NULL(in, false); 292 293 for (psS32 i = 0 ; i < out->n ; i++) { 294 psFree(out->spline[i]); 295 } 296 psFree(out->spline); 297 psFree(out->knots); 298 psFree(out->p_psDeriv2); 299 300 out->n = in->n; 301 out->spline = (psPolynomial1D **) psAlloc(in->n * sizeof(psPolynomial1D *)); 302 for (psS32 i = 0 ; i < in->n ; i++) { 303 out->spline[i] = Polynomial1DDup(in->spline[i]); 304 } 305 306 // XXX: use psVectorCopy if they get it working. 307 out->knots = psVectorAlloc(in->knots->n, in->knots->type.type); 308 for (psS32 i = 0 ; i < in->knots->n ; i++) { 309 out->knots->data.F32[i] = in->knots->data.F32[i]; 310 } 311 /* 312 out->knots = psVectorCopy(out->knots, in->knots, in->knots->type.type); 313 */ 314 315 out->p_psDeriv2 = (psF32 *) psAlloc((in->n + 1) * sizeof(psF32)); 316 // XXX: use memcpy 317 for (psS32 i = 0 ; i < (in->n + 1) ; i++) { 318 out->p_psDeriv2[i] = in->p_psDeriv2[i]; 319 } 320 321 return(true); 322 } 180 323 181 324 182 /****************************************************************************** … … 328 186 PM_FIT_POLYNOMIAL: fit a polynomial to the entire input vector data. 329 187 PM_FIT_SPLINE: fit splines to the input vector data. 330 The resulting spline or polynomial is set in the fitSpec argument. 188 XXX: Doesn't it make more sense to do polynomial interpolation on a few 189 elements of the input vector, rather than fit a polynomial to the entire 190 vector? 331 191 *****************************************************************************/ 332 static psVector *ScaleOverscanVector( 333 psVector *overscanVector, 334 psS32 n, 335 void *fitSpec, 336 pmFit fit) 192 static psVector *ScaleOverscanVector(psVector *overscanVector, 193 psS32 n, 194 void *fitSpec, 195 pmFit fit) 337 196 { 338 197 psTrace(".psModule.pmSubtracBias.ScaleOverscanVector", 4, 339 198 "---- ScaleOverscanVector() begin (%d -> %d) ----\n", overscanVector->n, n); 199 // PS_VECTOR_PRINT_F32(overscanVector); 340 200 341 201 if (NULL == overscanVector) { … … 350 210 // 351 211 if (n == overscanVector->n) { 352 return(psVectorCopy(newVec, overscanVector, PS_TYPE_F32)); 353 } 212 for (psS32 i = 0 ; i < n ; i++) { 213 newVec->data.F32[i] = overscanVector->data.F32[i]; 214 } 215 return(newVec); 216 } 217 psPolynomial1D *myPoly; 218 psSpline1D *mySpline; 354 219 psF32 x; 355 220 psS32 i; 356 221 if (fit == PM_FIT_POLYNOMIAL) { 357 222 // Fit a polynomial to the old overscan vector. 358 psPolynomial1D *myPoly = (psPolynomial1D *) fitSpec;223 myPoly = (psPolynomial1D *) fitSpec; 359 224 PS_ASSERT_POLY_NON_NULL(myPoly, NULL); 360 PS_ASSERT_POLY1D(myPoly, NULL);361 225 myPoly = psVectorFitPolynomial1D(myPoly, NULL, 0, overscanVector, NULL, NULL); 362 226 if (myPoly == NULL) { 363 psError(PS_ERR_UNKNOWN, false, " Could not fit a polynomial to the psVector.\n");227 psError(PS_ERR_UNKNOWN, false, "ScaleOverscanVector()(1): Could not fit a polynomial to the psVector.\n"); 364 228 return(NULL); 365 229 } … … 368 232 // of the old vector, use the fitted polynomial to determine the 369 233 // interpolated value at that point, and set the new vector. 370 for ( psS32i=0;i<n;i++) {234 for (i=0;i<n;i++) { 371 235 x = ((psF32) i) * ((psF32) overscanVector->n) / ((psF32) n); 372 236 newVec->data.F32[i] = psPolynomial1DEval(myPoly, x); 373 237 } 374 238 } else if (fit == PM_FIT_SPLINE) { 239 psS32 mustFreeSpline = 0; 240 // Fit a spline to the old overscan vector. 241 mySpline = (psSpline1D *) fitSpec; 242 // XXX: Does it make any sense to have a psSpline argument? 243 if (mySpline == NULL) { 244 mustFreeSpline = 1; 245 } 246 375 247 // 376 248 // NOTE: Since the X arg in the psVectorFitSpline1D() function is NULL, … … 378 250 // properly when doing the spline eval. 379 251 // 380 psSpline1D *mySpline = psVectorFitSpline1D(NULL, overscanVector); 252 // mySpline = psVectorFitSpline1D(mySpline, NULL, overscanVector, NULL); 253 mySpline = psVectorFitSpline1D(NULL, overscanVector); 381 254 if (mySpline == NULL) { 382 psError(PS_ERR_UNKNOWN, false, " Could not fit a spline to the psVector.\n");255 psError(PS_ERR_UNKNOWN, false, "ScaleOverscanVector()(2): Could not fit a spline to the psVector.\n"); 383 256 return(NULL); 384 257 } 258 // PS_PRINT_SPLINE(mySpline); 385 259 386 260 // For each element of the new vector, convert the x-ordinate to that 387 // of the old vector, use the fitted splineto determine the261 // of the old vector, use the fitted polynomial to determine the 388 262 // interpolated value at that point, and set the new vector. 389 for ( psS32i=0;i<n;i++) {263 for (i=0;i<n;i++) { 390 264 // Scale to [0 : overscanVector->n - 1] 391 265 x = ((psF32) i) * ((psF32) (overscanVector->n-1)) / ((psF32) n); 392 266 newVec->data.F32[i] = psSpline1DEval(mySpline, x); 393 267 } 394 395 psSpline1D *ptrSpline = (psSpline1D *) fitSpec; 396 if (ptrSpline != NULL) { 397 // Copy the resulting spline fit into ptrSpline. 398 PS_ASSERT_SPLINE(ptrSpline, NULL); 399 SplineCopy(ptrSpline, mySpline); 400 } 401 psFree(mySpline); 268 if (mustFreeSpline ==1) { 269 psFree(mySpline); 270 } 271 // PS_VECTOR_PRINT_F32(newVec); 272 273 402 274 } else { 403 275 psError(PS_ERR_UNKNOWN, true, "unknown fit type. Returning NULL.\n"); … … 412 284 413 285 /****************************************************************************** 286 XXX: The SDRS does not specify type support. F32 is implemented here. 414 287 *****************************************************************************/ 415 static psS32 GetOverscanSize( 416 psImage *inImg, 417 pmOverscanAxis overScanAxis) 418 { 419 if (overScanAxis == PM_OVERSCAN_ROWS) { 420 return(inImg->numCols); 421 } else if (overScanAxis == PM_OVERSCAN_COLUMNS) { 422 return(inImg->numRows); 423 } else if (overScanAxis == PM_OVERSCAN_ALL) { 424 return(1); 425 } 426 return(0); 427 } 428 429 /****************************************************************************** 430 GetOverscanAxis(in) this private routine determines the appropiate overscan 431 axis from the parent cell metadata. 432 433 XXX: Verify the READDIR corresponds with my overscan axis. 434 *****************************************************************************/ 435 static pmOverscanAxis GetOverscanAxis(pmReadout *in) 436 { 437 psBool rc; 438 if ((in->parent != NULL) && (in->parent->concepts)) { 439 psS32 dir = psMetadataLookupS32(&rc, in->parent->concepts, "CELL.READDIR"); 440 if (rc == true) { 441 if (dir == 1) { 442 return(PM_OVERSCAN_ROWS); 443 } else if (dir == 2) { 444 return(PM_OVERSCAN_COLUMNS); 445 } else if (dir == 3) { 446 return(PM_OVERSCAN_ALL); 447 } 448 } 449 } 450 451 psLogMsg(__func__, PS_LOG_WARN, 452 "WARNING: pmSubtractBias.(): could not determine CELL.READDIR from in->parent metadata. Setting overscan axis to PM_OVERSCAN_NONE.\n"); 453 return(PM_OVERSCAN_NONE); 454 } 455 456 /****************************************************************************** 457 psListLength(list): determine the length of a psList. 458 459 XXX: Put this elsewhere. 460 *****************************************************************************/ 461 static psS32 psListLength( 462 psList *list) 463 { 464 psS32 length = 0; 465 psListElem *tmpElem = (psListElem *) list->head; 466 while (NULL != tmpElem) { 467 tmpElem = tmpElem->next; 468 length++; 469 } 470 return(length); 471 } 472 473 /****************************************************************************** 474 Note: this isn't needed anymore as of psModule SDRS 12-09. 475 *****************************************************************************/ 476 static psBool OverscanReducePixel( 477 psImage *in, 478 psList *bias, 479 psStats *myStats) 480 { 481 PS_ASSERT_PTR_NON_NULL(in, NULL); 482 PS_ASSERT_PTR_NON_NULL(bias, NULL); 483 PS_ASSERT_PTR_NON_NULL(bias->head, NULL); 484 PS_ASSERT_PTR_NON_NULL(myStats, NULL); 485 486 // Allocate a psVector with one element per overscan image. 487 psS32 numOverscanImages = psListLength(bias); 488 psVector *statsAll = psVectorAlloc(numOverscanImages, PS_TYPE_F32); 489 psListElem *tmpOverscan = (psListElem *) bias->head; 490 psS32 i = 0; 491 psF64 statValue; 492 // 493 // We loop through each overscan image, calculating the specified 494 // statistic on that image. 495 // 496 while (NULL != tmpOverscan) { 497 psImage *myOverscanImage = (psImage *) tmpOverscan->data; 498 499 PS_ASSERT_IMAGE_TYPE(myOverscanImage, PS_TYPE_F32, NULL); 500 myStats = psImageStats(myStats, myOverscanImage, NULL, (psMaskType)0xffffffff); 501 if (myStats == NULL) { 502 psError(PS_ERR_UNKNOWN, false, "psImageStats(): could not perform requested statistical operation. Returning in image.\n"); 503 psFree(statsAll); 504 return(false); 505 } 506 if (false == p_psGetStatValue(myStats, &statValue)) { 507 psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation. Returning in image.\n"); 508 psFree(statsAll); 509 return(false); 510 } 511 statsAll->data.F32[i] = statValue; 512 i++; 513 tmpOverscan = tmpOverscan->next; 514 } 515 516 // 517 // We reduce the individual stats for each overscan image to 518 // a single psF32. 519 // 520 myStats = psVectorStats(myStats, statsAll, NULL, NULL, 0); 521 if (myStats == NULL) { 522 psError(PS_ERR_UNKNOWN, false, "psImageStats(): could not perform requested statistical operation. Returning in image.\n"); 523 psFree(statsAll); 524 return(false); 525 } 526 if (false == p_psGetStatValue(myStats, &statValue)) { 527 psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation. Returning in image.\n"); 528 psFree(statsAll); 529 return(false); 530 } 531 532 // 533 // Subtract the result and return. 534 // 535 ImageSubtractScalar(in, statValue); 536 psFree(statsAll); 537 return(in); 538 } 539 540 /****************************************************************************** 541 ReduceOverscanImageToCol(overscanImage, myStats): This private routine reduces 542 a single psImage to a column by combining all pixels from each row into a 543 single pixel via requested statistic in myStats. 544 *****************************************************************************/ 545 static psVector *ReduceOverscanImageToCol( 546 psImage *overscanImage, 547 psStats *myStats) 548 { 549 psF64 statValue; 550 psVector *tmpRow = psVectorAlloc(overscanImage->numCols, PS_TYPE_F32); 551 psVector *tmpCol = psVectorAlloc(overscanImage->numRows, PS_TYPE_F32); 552 553 // 554 // For each row, we store all pixels in that row into a temporary psVector, 555 // then we run psVectorStats() on that vector. 556 // 557 for (psS32 i=0;i<overscanImage->numRows;i++) { 558 for (psS32 j=0;j<overscanImage->numCols;j++) { 559 tmpRow->data.F32[j] = overscanImage->data.F32[i][j]; 560 } 561 562 psStats *rc = psVectorStats(myStats, tmpRow, NULL, NULL, 0); 563 if (rc == NULL) { 564 psError(PS_ERR_UNKNOWN, true, "psVectorStats() could not perform requested statistical operation. Returning in image.\n"); 565 return(NULL); 566 } 567 568 if (false == p_psGetStatValue(rc, &statValue)) { 569 psError(PS_ERR_UNKNOWN, true, "p_psGetStatValue() could not determine result from requested statistical operation. Returning in image.\n"); 570 return(NULL); 571 } 572 573 tmpCol->data.F32[i] = (psF32) statValue; 574 } 575 psFree(tmpRow); 576 577 return(tmpCol); 578 } 579 580 /****************************************************************************** 581 ReduceOverscanImageToCol(overscanImage, myStats): This private routine reduces 582 a single psImage to a row by combining all pixels from each column into a 583 single pixel via requested statistic in myStats. 584 *****************************************************************************/ 585 static psVector *ReduceOverscanImageToRow( 586 psImage *overscanImage, 587 psStats *myStats) 588 { 589 psF64 statValue; 590 psVector *tmpRow = psVectorAlloc(overscanImage->numCols, PS_TYPE_F32); 591 psVector *tmpCol = psVectorAlloc(overscanImage->numRows, PS_TYPE_F32); 592 593 // 594 // For each column, we store all pixels in that column into a temporary psVector, 595 // then we run psVectorStats() on that vector. 596 // 597 for (psS32 i=0;i<overscanImage->numCols;i++) { 598 for (psS32 j=0;j<overscanImage->numRows;j++) { 599 tmpCol->data.F32[j] = overscanImage->data.F32[j][i]; 600 } 601 602 psStats *rc = psVectorStats(myStats, tmpCol, NULL, NULL, 0); 603 if (rc == NULL) { 604 psError(PS_ERR_UNKNOWN, true, "psVectorStats() could not perform requested statistical operation. Returning in image.\n"); 605 return(NULL); 606 } 607 608 if (false == p_psGetStatValue(rc, &statValue)) { 609 psError(PS_ERR_UNKNOWN, true, "p_psGetStatValue() could not determine result from requested statistical operation. Returning in image.\n"); 610 return(NULL); 611 } 612 613 tmpRow->data.F32[i] = (psF32) statValue; 614 } 615 psFree(tmpCol); 616 617 return(tmpRow); 618 } 619 620 /****************************************************************************** 621 OverscanReduce(vecSize, bias, myStats): This private routine takes a psList of 622 overscan images (in bias) and reduces them to a single psVector via the 623 specified psStats struct. The vector is then scaled to the length or the 624 row/column in inImg. 625 *****************************************************************************/ 626 static psVector* OverscanReduce( 627 psImage *inImg, 628 pmOverscanAxis overScanAxis, 629 psList *bias, 630 void *fitSpec, 631 pmFit fit, 632 psStats *myStats) 633 { 634 if ((overScanAxis != PM_OVERSCAN_ROWS) && (overScanAxis != PM_OVERSCAN_COLUMNS)) { 635 psError(PS_ERR_UNKNOWN, true, "overScanAxis must be PM_OVERSCAN_ROWS or PM_OVERSCAN_COLUMNS\n"); 636 return(NULL); 637 } 638 PS_ASSERT_PTR_NON_NULL(inImg, NULL); 639 PS_ASSERT_PTR_NON_NULL(bias, NULL); 640 PS_ASSERT_PTR_NON_NULL(bias->head, NULL); 641 PS_ASSERT_PTR_NON_NULL(myStats, NULL); 642 // 643 // Allocate a psVector for the output of this routine. 644 // 645 psS32 vecSize = GetOverscanSize(inImg, overScanAxis); 646 psVector *overscanVector = psVectorAlloc(vecSize, PS_TYPE_F32); 647 648 // 649 // Allocate an array of psVectors with one psVector per element of the 650 // final oversan column vector. These psVectors will be used with 651 // psStats to reduce the multiple elements from each overscan column 652 // vector to a single final column vector. 653 // 654 psS32 numOverscanImages = psListLength(bias); 655 psVector **overscanVectors = (psVector **) psAlloc(numOverscanImages * sizeof(psVector *)); 656 for (psS32 i = 0 ; i < numOverscanImages ; i++) { 657 overscanVectors[i] = NULL; 658 } 659 660 // 661 // We iterate through the list of overscan images. For each image, 662 // we reduce it to a single column or row. Save the overscan vector 663 // in overscanVectors[]. 664 // 665 psListElem *tmpOverscan = (psListElem *) bias->head; 666 psS32 overscanID = 0; 667 while (tmpOverscan != NULL) { 668 psImage *tmpOverscanImage = (psImage *) tmpOverscan->data; 669 if (overScanAxis == PM_OVERSCAN_ROWS) { 670 overscanVectors[overscanID] = ReduceOverscanImageToRow(tmpOverscanImage, myStats); 671 } else if (overScanAxis == PM_OVERSCAN_COLUMNS) { 672 overscanVectors[overscanID] = ReduceOverscanImageToCol(tmpOverscanImage, myStats); 673 } 674 675 tmpOverscan = tmpOverscan->next; 676 overscanID++; 677 } 678 679 // 680 // For each overscan vector, if necessary, we scale that column or 681 // row to vecSize. Note: we should have already ensured that the 682 // fit is poly or spline. 683 // 684 for (psS32 i = 0 ; i < numOverscanImages ; i++) { 685 psVector *tmpOverscanVector = overscanVectors[i]; 686 687 if (tmpOverscanVector->n != vecSize) { 688 overscanVectors[i] = ScaleOverscanVector(tmpOverscanVector, vecSize, fitSpec, fit); 689 if (overscanVectors[i] == NULL) { 690 psError(PS_ERR_UNKNOWN, false, "ScaleOverscanVector(): could not scale the overscan vector.\n"); 691 for (psS32 i = 0 ; i < numOverscanImages ; i++) { 692 psFree(overscanVectors[i]); 693 } 694 psFree(overscanVectors); 695 psFree(tmpOverscanVector); 696 return(NULL); 697 } 698 psFree(tmpOverscanVector); 699 } 700 } 701 702 // 703 // We collect all elements in the overscan vectors for the various 704 // overscan images into a single psVector (tmpVec). Then we call 705 // psStats on that vector to determine the final values for the 706 // overscan vector. 707 // 708 psVector *tmpVec = psVectorAlloc(numOverscanImages, PS_TYPE_F32); 709 psF64 statValue; 710 for (psS32 i = 0 ; i < vecSize ; i++) { 711 // Collect the i-th elements from each overscan vector into a single vector. 712 for (psS32 j = 0 ; j < numOverscanImages ; j++) { 713 tmpVec->data.F32[j] = overscanVectors[j]->data.F32[i]; 714 } 715 716 if (NULL == psVectorStats(myStats, tmpVec, NULL, NULL, 0)) { 717 psError(PS_ERR_UNKNOWN, false, "psVectorStats(): could not perform requested statistical operation. Returning in image.\n"); 718 for (psS32 i = 0 ; i < numOverscanImages ; i++) { 719 psFree(overscanVectors[i]); 720 } 721 psFree(overscanVectors); 722 psFree(tmpVec); 723 return(NULL); 724 } 725 if (false == p_psGetStatValue(myStats, &statValue)) { 726 psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation. Returning in image.\n"); 727 for (psS32 i = 0 ; i < numOverscanImages ; i++) { 728 psFree(overscanVectors[i]); 729 } 730 psFree(overscanVectors); 731 psFree(tmpVec); 732 return(NULL); 733 } 734 735 overscanVector->data.F32[i] = (psF32) statValue; 736 } 737 738 // 739 // We're done. Free the intermediate overscan vectors. 740 // 741 psFree(tmpVec); 742 for (psS32 i = 0 ; i < numOverscanImages ; i++) { 743 psFree(overscanVectors[i]); 744 } 745 psFree(overscanVectors); 746 747 // 748 // Return the computed overscanVector 749 // 750 return(overscanVector); 751 } 752 753 /****************************************************************************** 754 RebinOverscanVector(overscanVector, nBinOrig, myStats): this private routine 755 takes groups of nBinOrig elements in the input vector, combines them into a 756 single pixel via myStats and psVectorStats(), and then outputs a vector of 757 those pixels. 758 *****************************************************************************/ 759 static psS32 RebinOverscanVector( 760 psVector *overscanVector, 761 psS32 nBinOrig, 762 psStats *myStats) 763 { 764 psF64 statValue; 765 psS32 nBin; 766 if ((nBinOrig > 1) && (nBinOrig < overscanVector->n)) { 767 psS32 numBins = 1+((overscanVector->n)/nBinOrig); 768 psVector *myBin = psVectorAlloc(numBins, PS_TYPE_F32); 769 psVector *binVec = psVectorAlloc(nBinOrig, PS_TYPE_F32); 770 771 for (psS32 i=0;i<numBins;i++) { 772 for(psS32 j=0;j<nBinOrig;j++) { 773 if (overscanVector->n > ((i*nBinOrig)+j)) { 774 binVec->data.F32[j] = overscanVector->data.F32[(i*nBinOrig)+j]; 775 } else { 776 // XXX: we get here if nBinOrig does not evenly divide 777 // the overscanVector vector. This is the last bin. Should 778 // we change the binVec->n to acknowledge that? 779 binVec->n = j; 780 } 781 } 782 psStats *rc = psVectorStats(myStats, binVec, NULL, NULL, 0); 783 if (rc == NULL) { 784 psError(PS_ERR_UNKNOWN, false, "psVectorStats(): could not perform requested statistical operation. Returning in image.\n"); 785 return(-1); 786 } 787 if (false == p_psGetStatValue(rc, &statValue)) { 788 psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation. Returning in image.\n"); 789 return(-1); 790 } 791 myBin->data.F32[i] = statValue; 792 } 793 794 // Change the effective size of overscanVector. 795 overscanVector->n = numBins; 796 for (psS32 i=0;i<numBins;i++) { 797 overscanVector->data.F32[i] = myBin->data.F32[i]; 798 } 799 psFree(binVec); 800 psFree(myBin); 801 nBin = nBinOrig; 802 } else { 803 nBin = 1; 804 } 805 806 return(nBin); 807 } 808 809 /****************************************************************************** 810 FitOverscanVectorAndUnbin(inImg, overscanVector, overScanAxis, fitSpec, fit, 811 nBin): this private routine fits a psPolynomial or psSpline to the overscan 812 vector. It then creates a new vector, with a size determined by the input 813 image, evaluates the psPolynomial or psSpline at each element in that vector, 814 then returns that vector. 815 *****************************************************************************/ 816 static psVector *FitOverscanVectorAndUnbin( 817 psImage *inImg, 818 psVector *overscanVector, 819 pmOverscanAxis overScanAxis, 820 void *fitSpec, 821 pmFit fit, 822 psS32 nBin) 823 { 824 psPolynomial1D* myPoly = NULL; 825 psSpline1D *mySpline = NULL; 826 // 827 // Fit a polynomial or spline to the overscan vector. 828 // 829 if (fit == PM_FIT_POLYNOMIAL) { 830 myPoly = (psPolynomial1D *) fitSpec; 831 PS_ASSERT_POLY_NON_NULL(myPoly, NULL); 832 PS_ASSERT_POLY1D(myPoly, NULL); 833 myPoly = psVectorFitPolynomial1D(myPoly, NULL, 0, overscanVector, NULL, NULL); 834 if (myPoly == NULL) { 835 psError(PS_ERR_UNKNOWN, false, "Could not fit a polynomial to overscan vector. Returning NULL.\n"); 836 return(NULL); 837 } 838 } else if (fit == PM_FIT_SPLINE) { 839 mySpline = psVectorFitSpline1D(NULL, overscanVector); 840 if (mySpline == NULL) { 841 psError(PS_ERR_UNKNOWN, false, "Could not fit a spline to overscan vector. Returning NULL.\n"); 842 return(NULL); 843 } 844 if (fitSpec != NULL) { 845 // Copy the resulting spline fit into fitSpec. 846 psSpline1D *ptrSpline = (psSpline1D *) fitSpec; 847 PS_ASSERT_SPLINE(ptrSpline, NULL); 848 SplineCopy(ptrSpline, mySpline); 849 } 850 } 851 852 // 853 // Evaluate the poly/spline at each pixel in the overscan row/column. 854 // 855 psS32 vecSize = GetOverscanSize(inImg, overScanAxis); 856 psVector *newVec = psVectorAlloc(vecSize, PS_TYPE_F32); 857 if ((nBin > 1) && (nBin < overscanVector->n)) { 858 for (psS32 i = 0 ; i < vecSize ; i++) { 859 if (fit == PM_FIT_POLYNOMIAL) { 860 newVec->data.F32[i] = psPolynomial1DEval(myPoly, ((psF32) i) / ((psF32) nBin)); 861 } else if (fit == PM_FIT_SPLINE) { 862 newVec->data.F32[i] = psSpline1DEval(mySpline, ((psF32) i) / ((psF32) nBin)); 863 } 864 } 865 } else { 866 for (psS32 i = 0 ; i < vecSize ; i++) { 867 if (fit == PM_FIT_POLYNOMIAL) { 868 newVec->data.F32[i] = psPolynomial1DEval(myPoly, (psF32) i); 869 } else if (fit == PM_FIT_SPLINE) { 870 newVec->data.F32[i] = psSpline1DEval(mySpline, (psF32) i); 871 } 872 } 873 } 874 875 psFree(mySpline); 876 psFree(overscanVector); 877 return(newVec); 878 } 879 880 881 882 /****************************************************************************** 883 UnbinOverscanVector(inImg, overscanVector, overScanAxis, nBin): this private 884 routine takes a psVector overscanVector that was previously binned by a factor 885 of nBin, and then expands it to its original size, duplicated elements nBin 886 times for each element in the input vector overscanVector. 887 *****************************************************************************/ 888 static psVector *UnbinOverscanVector( 889 psImage *inImg, 890 psVector *overscanVector, 891 pmOverscanAxis overScanAxis, 892 psS32 nBin) 893 { 894 psS32 vecSize; 895 896 if (overScanAxis == PM_OVERSCAN_ROWS) { 897 vecSize = inImg->numCols; 898 } else if (overScanAxis == PM_OVERSCAN_COLUMNS) { 899 vecSize = inImg->numRows; 900 } 901 902 psVector *newVec = psVectorAlloc(vecSize, PS_TYPE_F32); 903 for (psS32 i = 0 ; i < vecSize ; i++) { 904 newVec->data.F32[i] = overscanVector->data.F32[i/nBin]; 905 } 906 907 psFree(overscanVector); 908 return(newVec); 909 } 910 911 912 /****************************************************************************** 913 SubtractVectorFromImage(inImg, overscanVector, overScanAxis): this private 914 routine subtracts the overscanVector column-wise or row-wise from inImg. 915 *****************************************************************************/ 916 static psImage *SubtractVectorFromImage( 917 psImage *inImg, 918 psVector *overscanVector, 919 pmOverscanAxis overScanAxis) 920 { 921 // 922 // Subtract overscan vector row-wise from the image. 923 // 924 if (overScanAxis == PM_OVERSCAN_ROWS) { 925 for (psS32 i=0;i<inImg->numCols;i++) { 926 for (psS32 j=0;j<inImg->numRows;j++) { 927 inImg->data.F32[j][i]-= overscanVector->data.F32[i]; 928 } 929 } 930 } 931 932 // 933 // Subtract overscan vector column-wise from the image. 934 // 935 if (overScanAxis == PM_OVERSCAN_COLUMNS) { 936 for (psS32 i=0;i<inImg->numRows;i++) { 937 for (psS32 j=0;j<inImg->numCols;j++) { 938 inImg->data.F32[i][j]-= overscanVector->data.F32[i]; 939 } 940 } 941 } 942 943 return(inImg); 944 } 945 946 947 948 typedef enum { 949 PM_ERROR_NO_SUBTRACTION, 950 PM_WARNING_NO_SUBTRACTION, 951 PM_ERROR_NO_BIAS_SUBTRACT, 952 PM_WARNING_NO_BIAS_SUBTRACT, 953 PM_ERROR_NO_DARK_SUBTRACT, 954 PM_WARNING_NO_DARK_SUBTRACT, 955 PM_OKAY 956 } pmSubtractBiasAssertStatus; 957 /****************************************************************************** 958 AssertCodeOverscan(....) this private routine verifies that the various input 959 parameters to pmSubtractBias() are correct for overscan subtraction. 960 *****************************************************************************/ 961 pmSubtractBiasAssertStatus AssertCodeOverscan( 962 pmReadout *in, 963 void *fitSpec, 964 pmFit fit, 965 bool overscan, 966 psStats *stat, 967 int nBinOrig, 968 const pmReadout *bias, 969 const pmReadout *dark) 970 { 971 972 PS_ASSERT_READOUT_NON_NULL(in, PM_ERROR_NO_SUBTRACTION); 973 PS_ASSERT_READOUT_NON_EMPTY(in, PM_ERROR_NO_SUBTRACTION); 974 PS_ASSERT_READOUT_TYPE(in, PS_TYPE_F32, PM_ERROR_NO_SUBTRACTION); 975 PS_WARN_PTR_NON_NULL(in->parent); 976 if (in->parent != NULL) { 977 PS_WARN_PTR_NON_NULL(in->parent->concepts); 978 } 979 980 if (overscan == true) { 981 pmOverscanAxis overScanAxis = GetOverscanAxis(in); 982 PS_ASSERT_PTR_NON_NULL(stat, PM_ERROR_NO_SUBTRACTION); 983 PS_ASSERT_PTR_NON_NULL(in->bias, PM_ERROR_NO_SUBTRACTION); 984 PS_ASSERT_PTR_NON_NULL(in->bias->head, PM_ERROR_NO_SUBTRACTION); 985 // 986 // Check the type, size of each bias image. 987 // 988 psListElem *tmpOverscan = (psListElem *) in->bias->head; 989 psS32 numOverscans = 0; 990 while (NULL != tmpOverscan) { 991 numOverscans++; 992 psImage *myOverscanImage = (psImage *) tmpOverscan->data; 993 PS_ASSERT_IMAGE_TYPE(myOverscanImage, PS_TYPE_F32, PM_ERROR_NO_SUBTRACTION); 994 // XXX: Get this right with the rows and columns. 995 if (overScanAxis == PM_OVERSCAN_ROWS) { 996 if (myOverscanImage->numRows != in->image->numRows) { 997 psLogMsg(__func__, PS_LOG_WARN, 998 "WARNING: pmSubtractBias.(): overscan image (# %d) has %d rows, input image has %d rows\n", 999 numOverscans, myOverscanImage->numCols, in->image->numRows); 1000 if (fit == PM_FIT_NONE) { 1001 psError(PS_ERR_UNKNOWN, true, "Don't know how to scale the overscan vectors. Set fit to PM_FIT_POLYNOMIAL or PM_FIT_SPLINE.\n"); 1002 return(PM_ERROR_NO_SUBTRACTION); 1003 } 1004 } 1005 } else if (overScanAxis == PM_OVERSCAN_COLUMNS) { 1006 if (myOverscanImage->numCols != in->image->numCols) { 1007 psLogMsg(__func__, PS_LOG_WARN, 1008 "WARNING: pmSubtractBias.(): overscan image (# %d) has %d columns, input image has %d columns\n", 1009 numOverscans, myOverscanImage->numCols, in->image->numCols); 1010 if (fit == PM_FIT_NONE) { 1011 psError(PS_ERR_UNKNOWN, true, "Don't know how to scale the overscan vectors. Set fit to PM_FIT_POLYNOMIAL or PM_FIT_SPLINE.\n"); 1012 return(PM_ERROR_NO_SUBTRACTION); 1013 } 1014 } 1015 } else if (overScanAxis != PM_OVERSCAN_ALL) { 1016 psError(PS_ERR_UNKNOWN, true, "Must specify and overscan axis.\n"); 1017 return(PM_ERROR_NO_SUBTRACTION); 1018 } 1019 tmpOverscan = tmpOverscan->next; 1020 } 1021 } else { 1022 if (fit != PM_FIT_NONE) { 1023 psLogMsg(__func__, PS_LOG_WARN, 1024 "WARNING: pmSubtractBias.(): overscan is FALSE and fit is not PM_FIT_NONE.\n"); 1025 return(PM_WARNING_NO_SUBTRACTION); 1026 } 1027 } 1028 1029 // XXX: I do not like the following spec since it's useless to specify 1030 // a psSpline as the fitSpec. 1031 if (0) { 1032 if ((fitSpec == NULL) && 1033 ((fit != PM_FIT_NONE) || (overscan == true))) { 1034 psError(PS_ERR_UNKNOWN, true, "fitSpec is NULL and fit is not PM_FIT_NONE or overscan is TRUE.\n"); 1035 return(PM_ERROR_NO_SUBTRACTION); 1036 } 1037 } 1038 1039 return(PM_OKAY); 1040 } 1041 1042 /****************************************************************************** 1043 AssertCodeBias(....) this private routine verifies that the various input 1044 parameters to pmSubtractBias() are correct for bias subtraction. 1045 *****************************************************************************/ 1046 static pmSubtractBiasAssertStatus AssertCodeBias( 1047 pmReadout *in, 1048 void *fitSpec, 1049 pmFit fit, 1050 bool overscan, 1051 psStats *stat, 1052 int nBinOrig, 1053 const pmReadout *bias, 1054 const pmReadout *dark) 1055 { 1056 if ((in->image->numRows + in->row0 - bias->row0) > bias->image->numRows) { 1057 psError(PS_ERR_UNKNOWN,true, "bias image does not have enough rows. Returning in image\n"); 1058 return(PM_ERROR_NO_BIAS_SUBTRACT); 1059 } 1060 if ((in->image->numCols + in->col0 - bias->col0) > bias->image->numCols) { 1061 psError(PS_ERR_UNKNOWN,true, "bias image does not have enough columns. Returning in image\n"); 1062 return(PM_ERROR_NO_BIAS_SUBTRACT); 1063 } 1064 1065 if (bias != NULL) { 1066 PS_ASSERT_READOUT_NON_EMPTY(bias, PM_ERROR_NO_BIAS_SUBTRACT); 1067 PS_ASSERT_READOUT_TYPE(bias, PS_TYPE_F32, PM_ERROR_NO_DARK_SUBTRACT); 1068 } 1069 return(PM_OKAY); 1070 } 1071 1072 /****************************************************************************** 1073 AssertCodeDark(....) this private routine verifies that the various input 1074 parameters to pmSubtractBias() are correct for dark subtraction. 1075 *****************************************************************************/ 1076 pmSubtractBiasAssertStatus AssertCodeDark( 1077 pmReadout *in, 1078 void *fitSpec, 1079 pmFit fit, 1080 bool overscan, 1081 psStats *stat, 1082 int nBinOrig, 1083 const pmReadout *bias, 1084 const pmReadout *dark) 1085 { 1086 if ((in->image->numRows + in->row0 - dark->row0) > dark->image->numRows) { 1087 psError(PS_ERR_UNKNOWN, true, "dark image does not have enough rows. Returning in image\n"); 1088 return(PM_ERROR_NO_DARK_SUBTRACT); 1089 } 1090 if ((in->image->numCols + in->col0 - dark->col0) > dark->image->numCols) { 1091 psError(PS_ERR_UNKNOWN, true, "dark image does not have enough columns. Returning in image\n"); 1092 return(PM_ERROR_NO_DARK_SUBTRACT); 1093 } 1094 1095 if (dark != NULL) { 1096 PS_ASSERT_READOUT_NON_EMPTY(dark, PM_ERROR_NO_DARK_SUBTRACT); 1097 PS_ASSERT_READOUT_TYPE(dark, PS_TYPE_F32, PM_ERROR_NO_DARK_SUBTRACT); 1098 } 1099 return(PM_OKAY); 1100 } 1101 1102 /****************************************************************************** 1103 p_psDetermineTrimmedImage(): global routine: determines the region of the 1104 input pmReadout which will be operated on by the various detrend modules. It 1105 does a metadata fetch on "CELL.TRIMSEC" for the parent cell of the pmReadout. 1106 1107 Use it this way: 1108 PS_WARN_PTR_NON_NULL(in->parent); 1109 if (in->parent != NULL) { 1110 PS_WARN_PTR_NON_NULL(in->parent->concepts); 1111 } 1112 // 1113 // Determine trimmed image from metadata. 1114 // 1115 psImage *trimmedImg = p_psDetermineTrimmedImage(in); 1116 1117 XXX: Create a pmUtils.c file and put this routine there. 1118 *****************************************************************************/ 1119 psImage *p_psDetermineTrimmedImage(pmReadout *in) 1120 { 1121 if ((in->parent == NULL) || (in->parent->concepts == NULL)) { 1122 psLogMsg(__func__, PS_LOG_WARN, 1123 "WARNING: could not determine CELL.TRIMSEC from parent cell Metadata (NULL).\n"); 1124 return(in->image); 1125 } 1126 1127 psBool rc = false; 1128 psImage *trimmedImg = NULL; 1129 psRegion *trimRegion = psMetadataLookupPtr(&rc, in->parent->concepts, 1130 "CELL.TRIMSEC"); 1131 if (rc == false) { 1132 psLogMsg(__func__, PS_LOG_WARN, 1133 "WARNING: could not determine CELL.TRIMSEC from parent cell Metadata.\n"); 1134 trimmedImg = in->image; 1135 } else { 1136 trimmedImg = psImageSubset(in->image, *trimRegion); 1137 } 1138 1139 return(trimmedImg); 1140 } 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 /****************************************************************************** 1160 pmSubtractBias(....): see SDRS for complete specification. 1161 1162 XXX: Code and assert type support: U16, S32, F32. 1163 XXX: Add trace messages. 1164 *****************************************************************************/ 1165 pmReadout *pmSubtractBias( 1166 pmReadout *in, 1167 void *fitSpec, 1168 pmFit fit, 1169 bool overscan, 1170 psStats *stat, 1171 int nBin, 1172 const pmReadout *bias, 1173 const pmReadout *dark) 288 pmReadout *pmSubtractBias(pmReadout *in, 289 void *fitSpec, 290 const psList *overscans, 291 pmOverscanAxis overScanAxis, 292 psStats *stat, 293 psS32 nBinOrig, 294 pmFit fit, 295 const pmReadout *bias) 1174 296 { 1175 297 psTrace(".psModule.pmSubtracBias.pmSubtractBias", 4, 1176 298 "---- pmSubtractBias() begin ----\n"); 1177 // 1178 // Check input parameters, generate warnings and errors. 1179 // 1180 if (PM_OKAY != AssertCodeOverscan(in, fitSpec, fit, overscan, stat, nBin, bias, dark)) { 1181 return(in); 1182 } 1183 // 1184 // Determine trimmed image from metadata. 1185 // 1186 psImage *trimmedImg = p_psDetermineTrimmedImage(in); 1187 1188 // 1189 // Subtract overscan frames if necessary. 1190 // 1191 if (overscan == true) { 1192 pmOverscanAxis overScanAxis = GetOverscanAxis(in); 299 PS_ASSERT_READOUT_NON_NULL(in, NULL); 300 PS_ASSERT_READOUT_NON_EMPTY(in, NULL); 301 PS_ASSERT_READOUT_TYPE(in, PS_TYPE_F32, NULL); 302 303 // 304 // If the overscans != NULL, then check the type of each image. 305 // 306 if (overscans != NULL) { 307 psListElem *tmpOverscan = (psListElem *) overscans->head; 308 while (NULL != tmpOverscan) { 309 psImage *myOverscanImage = (psImage *) tmpOverscan->data; 310 PS_ASSERT_IMAGE_TYPE(myOverscanImage, PS_TYPE_F32, NULL); 311 tmpOverscan = tmpOverscan->next; 312 } 313 } 314 315 if ((overscans == NULL) && (overScanAxis != PM_OVERSCAN_NONE)) { 316 psError(PS_ERR_UNKNOWN,true, "(overscans == NULL) && (overScanAxis != PM_OVERSCAN_NONE). Returning in image\n"); 317 return(in); 318 } 319 320 // Check for an unallowable pmFit. 321 if ((fit != PM_OVERSCAN_NONE) && 322 (fit != PM_OVERSCAN_ROWS) && 323 (fit != PM_OVERSCAN_COLUMNS) && 324 (fit != PM_OVERSCAN_ALL)) { 325 psError(PS_ERR_UNKNOWN, true, "fit is unallowable (%d). Returning in image.\n", fit); 326 return(in); 327 } 328 // Check for an unallowable pmOverscanAxis. 329 if ((overScanAxis != PM_OVERSCAN_NONE) && 330 (overScanAxis != PM_OVERSCAN_ROWS) && 331 (overScanAxis != PM_OVERSCAN_COLUMNS) && 332 (overScanAxis != PM_OVERSCAN_ALL)) { 333 psError(PS_ERR_UNKNOWN, true, "overScanAxis is unallowable (%d). Returning in image.\n", overScanAxis); 334 return(in); 335 } 336 psS32 i; 337 psS32 j; 338 psS32 numBins = 0; 339 static psVector *overscanVector = NULL; 340 psVector *tmpRow = NULL; 341 psVector *tmpCol = NULL; 342 psVector *myBin = NULL; 343 psVector *binVec = NULL; 344 psListElem *tmpOverscan = NULL; 345 double statValue; 346 psImage *myOverscanImage = NULL; 347 psPolynomial1D *myPoly = NULL; 348 psSpline1D *mySpline = NULL; 349 psS32 nBin; 350 351 // 352 // Create a static stats data structure and determine the highest 353 // priority stats option. 354 // 355 static psStats *myStats = NULL; 356 if (myStats == NULL) { 357 myStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN); 358 p_psMemSetPersistent(myStats, true); 359 } 360 if (stat != NULL) { 361 myStats->options = GenNewStatOptions(stat); 362 } 363 364 365 if (overScanAxis == PM_OVERSCAN_NONE) { 366 if (fit != PM_FIT_NONE) { 367 psLogMsg(__func__, PS_LOG_WARN, 368 "WARNING: pmSubtractBias.(): overScanAxis equals NONE, and fit does not equal NONE. Proceeding to full fram subtraction.\n"); 369 } 370 371 if (overscans != NULL) { 372 psLogMsg(__func__, PS_LOG_WARN, 373 "WARNING: pmSubtractBias.(): overScanAxis equals NONE and overscans does not equal NULL. Proceeding to full fram subtraction.\n"); 374 } 375 return(SubtractFrame(in, bias)); 376 } 377 378 if ((overScanAxis == PM_OVERSCAN_ALL) && (fit != PM_FIT_NONE)) { 379 psLogMsg(__func__, PS_LOG_WARN, 380 "WARNING: pmSubtractBias.(): overScanAxis equals ALL, and fit does not equal NONE. Proceeding with the rest of the module.\n"); 381 } 382 383 384 // 385 // We subtract each overscan region from the image data. 386 // If we get here we know that overscans != NULL. 387 // 388 389 if (overScanAxis == PM_OVERSCAN_ALL) { 390 tmpOverscan = (psListElem *) overscans->head; 391 while (NULL != tmpOverscan) { 392 myOverscanImage = (psImage *) tmpOverscan->data; 393 394 PS_ASSERT_IMAGE_TYPE(myOverscanImage, PS_TYPE_F32, NULL); 395 psStats *rc = psImageStats(myStats, myOverscanImage, NULL, (psMaskType)0xffffffff); 396 if (rc == NULL) { 397 psError(PS_ERR_UNKNOWN, false, "psImageStats(): could not perform requested statistical operation. Returning in image.\n"); 398 return(in); 399 } 400 if (false == p_psGetStatValue(myStats, &statValue)) { 401 psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation. Returning in image.\n"); 402 return(in); 403 } 404 ImageSubtractScalar(in->image, statValue); 405 406 tmpOverscan = tmpOverscan->next; 407 } 408 return(in); 409 } 410 411 // This check is redundant with above code. 412 if (!((overScanAxis == PM_OVERSCAN_ROWS) || (overScanAxis == PM_OVERSCAN_COLUMNS))) { 413 psError(PS_ERR_UNKNOWN, true, "overScanAxis is unallowable (%d).\nReturning in image.\n", overScanAxis); 414 return(in); 415 } 416 417 tmpOverscan = (psListElem *) overscans->head; 418 while (NULL != tmpOverscan) { 419 // PS_IMAGE_PRINT_F32_HIDEF(in->image); 420 myOverscanImage = (psImage *) tmpOverscan->data; 421 422 if (overScanAxis == PM_OVERSCAN_ROWS) { 423 if (myOverscanImage->numCols != (in->image)->numCols) { 424 psLogMsg(__func__, PS_LOG_WARN, 425 "WARNING: pmSubtractBias.(): overscan image has %d columns, input image has %d columns\n", 426 myOverscanImage->numCols, in->image->numCols); 427 } 428 429 // We create a row vector and subtract this vector from image. 430 // XXX: Is there a better way to extract a psVector from a psImage without 431 // having to copy every element in that vector? 432 overscanVector = psVectorAlloc(myOverscanImage->numCols, PS_TYPE_F32); 433 for (i=0;i<overscanVector->n;i++) { 434 overscanVector->data.F32[i] = 0.0; 435 } 436 tmpRow = psVectorAlloc(myOverscanImage->numRows, PS_TYPE_F32); 437 438 // For each column of the input image, loop through every row, 439 // collect the pixel in that row, then performed the specified 440 // statistical op on those pixels. Store this in overscanVector. 441 for (i=0;i<myOverscanImage->numCols;i++) { 442 for (j=0;j<myOverscanImage->numRows;j++) { 443 tmpRow->data.F32[j] = myOverscanImage->data.F32[j][i]; 444 } 445 psStats *rc = psVectorStats(myStats, tmpRow, NULL, NULL, 0); 446 if (rc == NULL) { 447 psError(PS_ERR_UNKNOWN, false, "psVectorStats(): could not perform requested statistical operation. Returning in image.\n"); 448 return(in); 449 } 450 if (false == p_psGetStatValue(rc, &statValue)) { 451 psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation. Returning in image.\n"); 452 return(in); 453 } 454 overscanVector->data.F32[i] = statValue; 455 } 456 psFree(tmpRow); 457 458 // Scale the overscan vector to the size of the input image. 459 if (overscanVector->n != in->image->numCols) { 460 if ((fit == PM_FIT_POLYNOMIAL) || (fit == PM_FIT_SPLINE)) { 461 psVector *newVec = ScaleOverscanVector(overscanVector, 462 in->image->numCols, 463 fitSpec, fit); 464 if (newVec == NULL) { 465 psError(PS_ERR_UNKNOWN, false, "ScaleOverscanVector(): could not scale the overscan vector. Returning in image.\n"); 466 return(in); 467 } 468 psFree(overscanVector); 469 overscanVector = newVec; 470 } else { 471 psError(PS_ERR_UNKNOWN, true, "Don't know how to scale the overscan vector. Set fit to PM_FIT_SPLINE or PM_FIT_POLYNOMIAL. Returning in image.\n"); 472 psFree(overscanVector); 473 return(in); 474 } 475 } 476 } 477 478 if (overScanAxis == PM_OVERSCAN_COLUMNS) { 479 if (myOverscanImage->numRows != (in->image)->numRows) { 480 psLogMsg(__func__, PS_LOG_WARN, 481 "WARNING: pmSubtractBias.(): overscan image has %d rows, input image has %d rows\n", 482 myOverscanImage->numRows, in->image->numRows); 483 } 484 485 // We create a column vector and subtract this vector from image. 486 overscanVector = psVectorAlloc(myOverscanImage->numRows, PS_TYPE_F32); 487 for (i=0;i<overscanVector->n;i++) { 488 overscanVector->data.F32[i] = 0.0; 489 } 490 tmpCol = psVectorAlloc(myOverscanImage->numCols, PS_TYPE_F32); 491 492 // For each row of the input image, loop through every column, 493 // collect the pixel in that row, then performed the specified 494 // statistical op on those pixels. Store this in overscanVector. 495 for (i=0;i<myOverscanImage->numRows;i++) { 496 for (j=0;j<myOverscanImage->numCols;j++) { 497 tmpCol->data.F32[j] = myOverscanImage->data.F32[i][j]; 498 } 499 psStats *rc = psVectorStats(myStats, tmpCol, NULL, NULL, 0); 500 if (rc == NULL) { 501 psError(PS_ERR_UNKNOWN, false, "psVectorStats(): could not perform requested statistical operation. Returning in image.\n"); 502 return(in); 503 } 504 if (false == p_psGetStatValue(rc, &statValue)) { 505 psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation. Returning in image.\n"); 506 return(in); 507 } 508 overscanVector->data.F32[i] = statValue; 509 } 510 psFree(tmpCol); 511 512 // Scale the overscan vector to the size of the input image. 513 if (overscanVector->n != in->image->numRows) { 514 if ((fit == PM_FIT_POLYNOMIAL) || (fit == PM_FIT_SPLINE)) { 515 psVector *newVec = ScaleOverscanVector(overscanVector, 516 in->image->numRows, 517 fitSpec, fit); 518 if (newVec == NULL) { 519 psError(PS_ERR_UNKNOWN, false, "ScaleOverscanVector(): could not scale the overscan vector. Returning in image.\n"); 520 return(in); 521 } 522 psFree(overscanVector); 523 overscanVector = newVec; 524 } else { 525 psError(PS_ERR_UNKNOWN, true, "Don't know how to scale the overscan vector. Set fit to PM_FIT_SPLINE or PM_FIT_POLYNOMIAL. Returning in image.\n"); 526 psFree(overscanVector); 527 return(in); 528 } 529 } 530 } 531 1193 532 // 1194 // Create a psStats data structure and determine the highest 1195 // priority stats option. 533 // Re-bin the overscan vector (change its length). 1196 534 // 1197 psStats *myStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN); 1198 if (stat != NULL) { 1199 myStats->options = GenNewStatOptions(stat); 1200 } 1201 535 // Only if nBinOrig > 1. 536 if ((nBinOrig > 1) && (nBinOrig < overscanVector->n)) { 537 numBins = 1+((overscanVector->n)/nBinOrig); 538 myBin = psVectorAlloc(numBins, PS_TYPE_F32); 539 binVec = psVectorAlloc(nBinOrig, PS_TYPE_F32); 540 541 for (i=0;i<numBins;i++) { 542 for(j=0;j<nBinOrig;j++) { 543 if (overscanVector->n > ((i*nBinOrig)+j)) { 544 binVec->data.F32[j] = overscanVector->data.F32[(i*nBinOrig)+j]; 545 } else { 546 // XXX: we get here if nBinOrig does not evenly divide 547 // the overscanVector vector. This is the last bin. Should 548 // we change the binVec->n to acknowledge that? 549 binVec->n = j; 550 } 551 } 552 psStats *rc = psVectorStats(myStats, binVec, NULL, NULL, 0); 553 if (rc == NULL) { 554 psError(PS_ERR_UNKNOWN, false, "psVectorStats(): could not perform requested statistical operation. Returning in image.\n"); 555 return(in); 556 } 557 if (false == p_psGetStatValue(rc, &statValue)) { 558 psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation. Returning in image.\n"); 559 return(in); 560 } 561 myBin->data.F32[i] = statValue; 562 } 563 564 // Change the effective size of overscanVector. 565 overscanVector->n = numBins; 566 for (i=0;i<numBins;i++) { 567 overscanVector->data.F32[i] = myBin->data.F32[i]; 568 } 569 psFree(binVec); 570 psFree(myBin); 571 nBin = nBinOrig; 572 } else { 573 nBin = 1; 574 } 575 576 // At this point the number of data points in overscanVector should be 577 // equal to the number of rows/columns (whatever is appropriate) in the 578 // image divided by numBins. 1202 579 // 1203 // Reduce overscan images to a single pixel, then subtract. 1204 // This code is no longer required as of SDRS 12-09. 580 581 1205 582 // 1206 if (overScanAxis == PM_OVERSCAN_ALL) { 1207 if (false == OverscanReducePixel(trimmedImg, in->bias, myStats)) { 1208 return(in); 1209 } 1210 psFree(myStats); 583 // This doesn't seem right. The only way to do a spline fit is if, 584 // by SDRS requirements, fitSpec is not-NULL> But in order for it 585 // to be non-NULL, someone must have called psSpline1DAlloc() with 586 // the min, max, and number of splines. 587 // 588 if (!((fitSpec == NULL) || (fit == PM_FIT_NONE))) { 589 // 590 // Fit a polynomial or spline to the overscan vector. 591 // 592 if (fit == PM_FIT_POLYNOMIAL) { 593 myPoly = (psPolynomial1D *) fitSpec; 594 myPoly = psVectorFitPolynomial1D(myPoly, NULL, 0, overscanVector, NULL, NULL); 595 if (myPoly == NULL) { 596 psError(PS_ERR_UNKNOWN, false, "(3) Could not fit a polynomial to overscan vector. Returning in image.\n"); 597 psFree(overscanVector); 598 return(in); 599 } 600 } else if (fit == PM_FIT_SPLINE) { 601 // XXX: This makes no sense 602 // XXX: must free mySpline? 603 mySpline = (psSpline1D *) fitSpec; 604 mySpline = psVectorFitSpline1D(NULL, overscanVector); 605 if (mySpline == NULL) { 606 psError(PS_ERR_UNKNOWN, false, "Could not fit a spline to overscan vector. Returning in image.\n"); 607 psFree(overscanVector); 608 return(in); 609 } 610 } 611 612 // 613 // Subtract fitted overscan vector row-wise from the image. 614 // 615 if (overScanAxis == PM_OVERSCAN_ROWS) { 616 for (i=0;i<(in->image)->numCols;i++) { 617 psF32 tmpF32 = 0.0; 618 if (fit == PM_FIT_POLYNOMIAL) { 619 tmpF32 = psPolynomial1DEval(myPoly, ((psF32) i) / ((psF32) nBin)); 620 } else if (fit == PM_FIT_SPLINE) { 621 tmpF32 = psSpline1DEval(mySpline, ((psF32) i) / ((psF32) nBin)); 622 } 623 for (j=0;j<(in->image)->numRows;j++) { 624 (in->image)->data.F32[j][i]-= tmpF32; 625 } 626 } 627 } 628 629 // 630 // Subtract fitted overscan vector column-wise from the image. 631 // 632 if (overScanAxis == PM_OVERSCAN_COLUMNS) { 633 for (i=0;i<(in->image)->numRows;i++) { 634 psF32 tmpF32 = 0.0; 635 if (fit == PM_FIT_POLYNOMIAL) { 636 tmpF32 = psPolynomial1DEval(myPoly, ((psF32) i) / ((psF32) nBin)); 637 } else if (fit == PM_FIT_SPLINE) { 638 tmpF32 = psSpline1DEval(mySpline, ((psF32) i) / ((psF32) nBin)); 639 } 640 641 for (j=0;j<(in->image)->numCols;j++) { 642 (in->image)->data.F32[i][j]-= tmpF32; 643 } 644 } 645 } 1211 646 } else { 1212 647 // 1213 // Reduce the overscan images to a single overscan vector. 1214 // 1215 psVector *overscanVector = OverscanReduce(in->image, overScanAxis, 1216 in->bias, fitSpec, 1217 fit, myStats); 1218 if (overscanVector == NULL) { 1219 psError(PS_ERR_UNKNOWN, false, "Could not reduce overscan images to a single overscan vector. Returning in image\n"); 1220 psFree(myStats); 1221 return(in); 1222 } 1223 1224 // 1225 // Rebin the overscan vector if necessary. 1226 // 1227 psS32 newBin = RebinOverscanVector(overscanVector, nBin, myStats); 1228 if (newBin < 0) { 1229 psError(PS_ERR_UNKNOWN, false, "Could rebin the overscan vector. Returning in image\n"); 1230 psFree(myStats); 1231 return(in); 1232 } 1233 1234 // 1235 // If necessary, fit a psPolynomial or psSpline to the overscan vector. 1236 // Then, unbin the overscan vector to appropriate length for the in image. 1237 // 1238 if ((fit == PM_FIT_POLYNOMIAL) || (fit == PM_FIT_SPLINE)) { 1239 overscanVector = FitOverscanVectorAndUnbin(trimmedImg, overscanVector, overScanAxis, fitSpec, fit, newBin); 1240 if (overscanVector == NULL) { 1241 psError(PS_ERR_UNKNOWN, false, "Could not fit the polynomial or spline to the overscan vector. Returning in image\n"); 1242 psFree(myStats); 1243 return(in); 1244 } 1245 } else { 1246 overscanVector = UnbinOverscanVector(trimmedImg, overscanVector, overScanAxis, newBin); 1247 } 1248 1249 // 1250 // Subtract the overscan vector from the input image. 1251 // 1252 SubtractVectorFromImage(trimmedImg, overscanVector, overScanAxis); 1253 psFree(myStats); 1254 psFree(overscanVector); 1255 } 1256 } 1257 1258 // 1259 // Perform bias subtraction if necessary. 1260 // 1261 if (bias != NULL) { 1262 if (PM_OKAY == AssertCodeBias(in, fitSpec, fit, overscan, stat, nBin, bias, dark)) { 1263 SubtractFrame(in, bias); 1264 } 1265 } 1266 1267 // 1268 // Perform dark subtraction if necessary. 1269 // 1270 if (dark != NULL) { 1271 if (PM_OKAY == AssertCodeDark(in, fitSpec, fit, overscan, stat, nBin, bias, dark)) { 1272 psBool rc; 1273 psF32 scale = 0.0; 1274 if (in->parent != NULL) { 1275 scale = psMetadataLookupS32(&rc, in->parent->concepts, "CELL.DARKTIME"); 1276 if (rc == false) { 1277 psLogMsg(__func__, PS_LOG_WARN, 1278 "WARNING: pmSubtractBias.(): could not determine CELL.FARKTIME from in->parent metadata.\n"); 1279 } 1280 } 1281 SubtractDarkFrame(in, dark, scale); 1282 } 1283 } 1284 1285 // 1286 // All done. 1287 // 648 // If we get here, then no polynomials were fit to the overscan 649 // vector. We simply subtract it, taking into account binning, 650 // from the image. 651 // 652 653 // 654 // Subtract overscan vector row-wise from the image. 655 // 656 if (overScanAxis == PM_OVERSCAN_ROWS) { 657 for (i=0;i<(in->image)->numCols;i++) { 658 for (j=0;j<(in->image)->numRows;j++) { 659 (in->image)->data.F32[j][i]-= overscanVector->data.F32[i/nBin]; 660 } 661 } 662 } 663 664 // 665 // Subtract overscan vector column-wise from the image. 666 // 667 if (overScanAxis == PM_OVERSCAN_COLUMNS) { 668 for (i=0;i<(in->image)->numRows;i++) { 669 for (j=0;j<(in->image)->numCols;j++) { 670 (in->image)->data.F32[i][j]-= overscanVector->data.F32[i/nBin]; 671 } 672 } 673 } 674 } 675 676 psFree(overscanVector); 677 678 tmpOverscan = tmpOverscan->next; 679 } 680 1288 681 psTrace(".psModule.pmSubtracBias.pmSubtractBias", 4, 1289 682 "---- pmSubtractBias() exit ----\n"); 683 684 if (bias != NULL) { 685 return(SubtractFrame(in, bias)); 686 } 1290 687 return(in); 1291 688 }
Note:
See TracChangeset
for help on using the changeset viewer.
