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