Changeset 25999 for trunk/psModules/src/imcombine/pmSubtractionEquation.c
- Timestamp:
- Nov 2, 2009, 10:38:23 AM (17 years ago)
- Location:
- trunk/psModules/src/imcombine
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
pmSubtractionEquation.c (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/imcombine
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/czw_branch/cleanup/psModules/src/imcombine merged eligible /branches/eam_branches/20090522/psModules/src/imcombine merged eligible /branches/eam_branches/20090715/psModules/src/imcombine merged eligible /branches/eam_branches/20090820/psModules/src/imcombine merged eligible /branches/pap/psModules/src/imcombine merged eligible /branches/pap_mops/psModules/src/imcombine 25137-25255
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/psModules/src/imcombine/pmSubtractionEquation.c
r24844 r25999 15 15 #include "pmSubtractionVisual.h" 16 16 17 // #define TESTING // TESTING output for debugging; may not work with threads!17 //#define TESTING // TESTING output for debugging; may not work with threads! 18 18 19 19 #define USE_VARIANCE // Include variance in equation? 20 20 21 21 22 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// … … 23 24 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 24 25 25 // Calculate the sum over a stamp product 26 static inline double calculateSumProduct(const psKernel *image1, // First image in multiplication 27 const psKernel *image2, // Second image in multiplication 28 const psKernel *variance, // Variance image 29 int footprint // (Half-)Size of stamp 30 ) 26 // Calculate the least-squares matrix and vector 27 static bool calculateMatrixVector(psImage *matrix, // Least-squares matrix, updated 28 psVector *vector, // Least-squares vector, updated 29 const psKernel *input, // Input image (target) 30 const psKernel *reference, // Reference image (convolution source) 31 const psKernel *variance, // Variance image 32 const psArray *convolutions, // Convolutions for each kernel 33 const pmSubtractionKernels *kernels, // Kernels 34 const psImage *polyValues, // Spatial polynomial values 35 int footprint // (Half-)Size of stamp 36 ) 31 37 { 32 double sum = 0.0; // Sum of the image products 38 // (I - R * sum_i a_i k_i - g) (R * k_j) = 0 39 // I C_j = sum_i C_i C_j 40 41 // Background: C_i = 1.0 42 // Normalisation: C_i = R 43 44 int numKernels = kernels->num; // Number of kernels 45 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 46 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 47 int spatialOrder = kernels->spatialOrder; // Order of spatial variation 48 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 49 double poly[numPoly]; // Polynomial terms 50 double poly2[numPoly][numPoly]; // Polynomial-polynomial values 51 52 // Evaluate polynomial-polynomial terms 53 for (int iyOrder = 0, iIndex = 0; iyOrder <= spatialOrder; iyOrder++) { 54 for (int ixOrder = 0; ixOrder <= spatialOrder - iyOrder; ixOrder++, iIndex++) { 55 double iPoly = polyValues->data.F64[iyOrder][ixOrder]; // Value of polynomial 56 poly[iIndex] = iPoly; 57 for (int jyOrder = 0, jIndex = 0; jyOrder <= spatialOrder; jyOrder++) { 58 for (int jxOrder = 0; jxOrder <= spatialOrder - jyOrder; jxOrder++, jIndex++) { 59 double jPoly = polyValues->data.F64[jyOrder][jxOrder]; 60 poly2[iIndex][jIndex] = iPoly * jPoly; 61 } 62 } 63 } 64 } 65 66 67 for (int i = 0; i < numKernels; i++) { 68 psKernel *iConv = convolutions->data[i]; // Convolution for index i 69 for (int j = i; j < numKernels; j++) { 70 psKernel *jConv = convolutions->data[j]; // Convolution for index j 71 72 double sumCC = 0.0; // Sum of convolution products 73 for (int y = - footprint; y <= footprint; y++) { 74 for (int x = - footprint; x <= footprint; x++) { 75 double cc = iConv->kernel[y][x] * jConv->kernel[y][x]; 76 #ifdef USE_VARIANCE 77 cc /= variance->kernel[y][x]; 78 #endif 79 sumCC += cc; 80 } 81 } 82 83 // Spatial variation 84 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 85 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 86 double value = sumCC * poly2[iTerm][jTerm]; 87 matrix->data.F64[iIndex][jIndex] = value; 88 matrix->data.F64[jIndex][iIndex] = value; 89 } 90 } 91 } 92 93 double sumRC = 0.0; // Sum of the reference-convolution products 94 double sumIC = 0.0; // Sum of the input-convolution products 95 double sumC = 0.0; // Sum of the convolution 96 for (int y = - footprint; y <= footprint; y++) { 97 for (int x = - footprint; x <= footprint; x++) { 98 float conv = iConv->kernel[y][x]; 99 float in = input->kernel[y][x]; 100 float ref = reference->kernel[y][x]; 101 double ic = in * conv; 102 double rc = ref * conv; 103 double c = conv; 104 #ifdef USE_VARIANCE 105 float varVal = 1.0 / variance->kernel[y][x]; 106 ic *= varVal; 107 rc *= varVal; 108 c *= varVal; 109 #endif 110 sumIC += ic; 111 sumRC += rc; 112 sumC += c; 113 } 114 } 115 // Spatial variation 116 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 117 double normTerm = sumRC * poly[iTerm]; 118 double bgTerm = sumC * poly[iTerm]; 119 matrix->data.F64[iIndex][normIndex] = normTerm; 120 matrix->data.F64[normIndex][iIndex] = normTerm; 121 matrix->data.F64[iIndex][bgIndex] = bgTerm; 122 matrix->data.F64[bgIndex][iIndex] = bgTerm; 123 vector->data.F64[iIndex] = sumIC * poly[iTerm]; 124 } 125 } 126 127 double sumRR = 0.0; // Sum of the reference product 128 double sumIR = 0.0; // Sum of the input-reference product 129 double sum1 = 0.0; // Sum of the background 130 double sumR = 0.0; // Sum of the reference 131 double sumI = 0.0; // Sum of the input 33 132 for (int y = - footprint; y <= footprint; y++) { 34 133 for (int x = - footprint; x <= footprint; x++) { 35 double value = image1->kernel[y][x] * image2->kernel[y][x]; 134 double in = input->kernel[y][x]; 135 double ref = reference->kernel[y][x]; 136 double ir = in * ref; 137 double rr = PS_SQR(ref); 138 double one = 1.0; 36 139 #ifdef USE_VARIANCE 37 value /= variance->kernel[y][x]; 38 #endif 39 sum += value; 40 } 41 } 42 return sum; 43 } 44 45 // Calculate a single element of the least-squares matrix, with the polynomial expansions in one direction 46 static inline bool calculateMatrixElement1(psImage *matrix, // Matrix to calculate 47 int i, int j, // Coordinates of element 48 const psKernel *image1, // First image in multiplication 49 const psKernel *image2, // Second image in multiplication 50 const psKernel *variance, // Variance image 51 const psImage *polyValues, // Spatial polynomial values 52 int numKernels, // Number of kernel basis functions 53 int footprint, // (Half-)Size of stamp 54 int spatialOrder, // Maximum order of spatial variation 55 bool symmetric // Is the matrix symmetric? 56 ) 57 { 58 double sum = calculateSumProduct(image1, image2, variance, footprint); // Sum of the image products 59 if (!isfinite(sum)) { 60 return false; 61 } 62 63 // Generate the pseudo-convolutions from the spatial polynomial terms 64 for (int iyOrder = 0, iIndex = i; iyOrder <= spatialOrder; iyOrder++) { 65 for (int ixOrder = 0; ixOrder <= spatialOrder - iyOrder; ixOrder++, iIndex += numKernels) { 66 double convPoly = sum * polyValues->data.F64[iyOrder][ixOrder]; 67 68 assert(iIndex < matrix->numRows && j < matrix->numCols); 69 70 matrix->data.F64[iIndex][j] = convPoly; 71 if (symmetric) { 72 73 assert(iIndex < matrix->numCols && j < matrix->numRows); 74 75 matrix->data.F64[j][iIndex] = convPoly; 76 } 77 } 78 } 140 float varVal = 1.0 / variance->kernel[y][x]; 141 rr *= varVal; 142 ir *= varVal; 143 in *= varVal; 144 ref *= varVal; 145 one *= varVal; 146 #endif 147 sumRR += rr; 148 sumIR += ir; 149 sumR += ref; 150 sumI += in; 151 sum1 += one; 152 } 153 } 154 matrix->data.F64[normIndex][normIndex] = sumRR; 155 matrix->data.F64[bgIndex][bgIndex] = sum1; 156 matrix->data.F64[normIndex][bgIndex] = matrix->data.F64[bgIndex][normIndex] = sumR; 157 vector->data.F64[normIndex] = sumIR; 158 vector->data.F64[bgIndex] = sumI; 159 79 160 return true; 80 161 } 81 162 82 // Calculate a single element of the least-squares matrix, with the polynomial expansions in both directions 83 static inline bool calculateMatrixElement2(psImage *matrix, // Matrix to calculate 84 int i, int j, // Coordinates of element 85 const psKernel *image1, // First image in multiplication 86 const psKernel *image2, // Second image in multiplication 87 const psKernel *variance, // Variance image 88 const psImage *polyValues, // Spatial polynomial values 89 int numKernels, // Number of kernel basis functions 90 int footprint, // (Half-)Size of stamp 91 int spatialOrder, // Maximum order of spatial variation 92 bool symmetric // Is the matrix symmetric? 93 ) 163 // Calculate the least-squares matrix and vector for dual convolution 164 static bool calculateDualMatrixVector(psImage *matrix1, // Least-squares matrix, updated 165 psVector *vector1, // Least-squares vector, updated 166 psImage *matrix2, // Least-squares matrix, updated 167 psVector *vector2, // Least-squares vector, updated 168 psImage *matrixX, // Cross-matrix 169 const psKernel *image1, // Image 1 170 const psKernel *image2, // Image 2 171 const psKernel *variance, // Variance image 172 const psArray *convolutions1, // Convolutions of image 1 for each kernel 173 const psArray *convolutions2, // Convolutions of image 2 for each kernel 174 const pmSubtractionKernels *kernels, // Kernels 175 const psImage *polyValues, // Spatial polynomial values 176 int footprint // (Half-)Size of stamp 177 ) 94 178 { 95 double sum = calculateSumProduct(image1, image2, variance, footprint); // Sum of the image products 96 if (!isfinite(sum)) { 97 return false; 98 } 99 100 // Generate the pseudo-convolutions from the spatial polynomial terms 101 for (int iyOrder = 0, iIndex = i; iyOrder <= spatialOrder; iyOrder++) { 102 for (int ixOrder = 0; ixOrder <= spatialOrder - iyOrder; ixOrder++, iIndex += numKernels) { 179 // A_ij = A_i A_j 180 // B_ij = B_i B_j 181 // C_ij = A_i B_j 182 // d_i = A_i I_2 183 // e_i = B_i I_2 184 185 // A_i = I_1 * k_i 186 // B_i = I_2 * k_i 187 188 // Background: A_i = 1.0 189 // Normalisation: A_i = I_1 190 191 int numKernels = kernels->num; // Number of kernels 192 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 193 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 194 int spatialOrder = kernels->spatialOrder; // Order of spatial variation 195 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 196 double poly[numPoly]; // Polynomial terms 197 double poly2[numPoly][numPoly]; // Polynomial-polynomial values 198 199 // Evaluate polynomial-polynomial terms 200 for (int iyOrder = 0, iIndex = 0; iyOrder <= spatialOrder; iyOrder++) { 201 for (int ixOrder = 0; ixOrder <= spatialOrder - iyOrder; ixOrder++, iIndex++) { 103 202 double iPoly = polyValues->data.F64[iyOrder][ixOrder]; // Value of polynomial 104 for (int jyOrder = 0, jIndex = j; jyOrder <= spatialOrder; jyOrder++) { 105 for (int jxOrder = 0; jxOrder <= spatialOrder - jyOrder; jxOrder++, jIndex += numKernels) { 106 double convPoly = sum * iPoly * polyValues->data.F64[jyOrder][jxOrder]; 107 108 assert(iIndex < matrix->numRows && jIndex < matrix->numCols); 109 110 matrix->data.F64[iIndex][jIndex] = convPoly; 111 if (symmetric) { 112 113 assert(iIndex < matrix->numCols && jIndex < matrix->numRows); 114 115 matrix->data.F64[jIndex][iIndex] = convPoly; 116 } 117 } 118 } 119 } 120 } 203 poly[iIndex] = iPoly; 204 for (int jyOrder = 0, jIndex = 0; jyOrder <= spatialOrder; jyOrder++) { 205 for (int jxOrder = 0; jxOrder <= spatialOrder - jyOrder; jxOrder++, jIndex++) { 206 double jPoly = polyValues->data.F64[jyOrder][jxOrder]; 207 poly2[iIndex][jIndex] = iPoly * jPoly; 208 } 209 } 210 } 211 } 212 213 214 for (int i = 0; i < numKernels; i++) { 215 psKernel *iConv1 = convolutions1->data[i]; // Convolution 1 for index i 216 psKernel *iConv2 = convolutions2->data[i]; // Convolution 2 for index i 217 for (int j = i; j < numKernels; j++) { 218 psKernel *jConv1 = convolutions1->data[j]; // Convolution 1 for index j 219 psKernel *jConv2 = convolutions2->data[j]; // Convolution 2 for index j 220 221 double sumAA = 0.0; // Sum of convolution products for matrix A 222 double sumBB = 0.0; // Sum of convolution products for matrix B 223 double sumAB = 0.0; // Sum of convolution products for matrix C 224 for (int y = - footprint; y <= footprint; y++) { 225 for (int x = - footprint; x <= footprint; x++) { 226 double aa = iConv1->kernel[y][x] * jConv1->kernel[y][x]; 227 double bb = iConv2->kernel[y][x] * jConv2->kernel[y][x]; 228 double ab = iConv1->kernel[y][x] * jConv2->kernel[y][x]; 229 #ifdef USE_VARIANCE 230 aa /= variance->kernel[y][x]; 231 bb /= variance->kernel[y][x]; 232 ab /= variance->kernel[y][x]; 233 #endif 234 sumAA += aa; 235 sumBB += bb; 236 sumAB += ab; 237 } 238 } 239 240 // Spatial variation 241 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 242 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 243 double aa = sumAA * poly2[iTerm][jTerm]; 244 double bb = sumBB * poly2[iTerm][jTerm]; 245 double ab = sumAB * poly2[iTerm][jTerm]; 246 matrix1->data.F64[iIndex][jIndex] = aa; 247 matrix1->data.F64[jIndex][iIndex] = aa; 248 matrix2->data.F64[iIndex][jIndex] = bb; 249 matrix2->data.F64[jIndex][iIndex] = bb; 250 matrixX->data.F64[iIndex][jIndex] = ab; 251 } 252 } 253 } 254 for (int j = 0; j < i; j++) { 255 psKernel *jConv2 = convolutions2->data[j]; // Convolution 2 for index j 256 double sumAB = 0.0; // Sum of convolution products for matrix C 257 for (int y = - footprint; y <= footprint; y++) { 258 for (int x = - footprint; x <= footprint; x++) { 259 double ab = iConv1->kernel[y][x] * jConv2->kernel[y][x]; 260 #ifdef USE_VARIANCE 261 ab /= variance->kernel[y][x]; 262 #endif 263 sumAB += ab; 264 } 265 } 266 267 // Spatial variation 268 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 269 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 270 double ab = sumAB * poly2[iTerm][jTerm]; 271 matrixX->data.F64[iIndex][jIndex] = ab; 272 } 273 } 274 } 275 276 double sumAI2 = 0.0; // Sum of A.I_2 products (for vector 1) 277 double sumBI2 = 0.0; // Sum of B.I_2 products (for vector 2) 278 double sumAI1 = 0.0; // Sum of A.I_1 products (for matrix 1, normalisation) 279 double sumA = 0.0; // Sum of A (for matrix 1, background) 280 double sumBI1 = 0.0; // Sum of B.I_1 products (for matrix X, normalisation) 281 double sumB = 0.0; // Sum of B products (for matrix X, background) 282 double sumI2 = 0.0; // Sum of I_2 (for vector 1, background) 283 double sumI1I2 = 0.0; // Sum of I_1.I_2 (for vector 1, normalisation) 284 for (int y = - footprint; y <= footprint; y++) { 285 for (int x = - footprint; x <= footprint; x++) { 286 float a = iConv1->kernel[y][x]; 287 float b = iConv2->kernel[y][x]; 288 float i1 = image1->kernel[y][x]; 289 float i2 = image2->kernel[y][x]; 290 291 double ai2 = a * i2; 292 double bi2 = b * i2; 293 double ai1 = a * i1; 294 double bi1 = b * i1; 295 double i1i2 = i1 * i2; 296 297 #ifdef USE_VARIANCE 298 float varVal = 1.0 / variance->kernel[y][x]; 299 ai2 *= varVal; 300 bi2 *= varVal; 301 ai1 *= varVal; 302 bi1 *= varVal; 303 i1i2 *= varVal; 304 a *= varVal; 305 b *= varVal; 306 i2 *= varVal; 307 #endif 308 309 sumAI2 += ai2; 310 sumBI2 += bi2; 311 sumAI1 += ai1; 312 sumA += a; 313 sumBI1 += bi1; 314 sumB += b; 315 sumI2 += i2; 316 sumI1I2 += i1i2; 317 } 318 } 319 // Spatial variation 320 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 321 double ai2 = sumAI2 * poly[iTerm]; 322 double bi2 = sumBI2 * poly[iTerm]; 323 double ai1 = sumAI1 * poly[iTerm]; 324 double a = sumA * poly[iTerm]; 325 double bi1 = sumBI1 * poly[iTerm]; 326 double b = sumB * poly[iTerm]; 327 328 matrix1->data.F64[iIndex][normIndex] = ai1; 329 matrix1->data.F64[normIndex][iIndex] = ai1; 330 matrix1->data.F64[iIndex][bgIndex] = a; 331 matrix1->data.F64[bgIndex][iIndex] = a; 332 vector1->data.F64[iIndex] = ai2; 333 vector2->data.F64[iIndex] = bi2; 334 matrixX->data.F64[iIndex][normIndex] = bi1; 335 matrixX->data.F64[iIndex][bgIndex] = b; 336 } 337 } 338 339 double sumI1 = 0.0; // Sum of I_1 (for matrix 1, background-normalisation) 340 double sumI1I1 = 0.0; // Sum of I_1^2 (for matrix 1, normalisation-normalisation) 341 double sum1 = 0.0; // Sum of 1 (for matrix 1, background-background) 342 double sumI2 = 0.0; // Sum of I_2 (for vector 1, background) 343 double sumI1I2 = 0.0; // Sum of I_1.I_2 (for vector 1, normalisation) 344 for (int y = - footprint; y <= footprint; y++) { 345 for (int x = - footprint; x <= footprint; x++) { 346 float i1 = image1->kernel[y][x]; 347 float i2 = image2->kernel[y][x]; 348 349 double i1i1 = i1 * i1; 350 double one = 1.0; 351 double i1i2 = i1 * i2; 352 353 #ifdef USE_VARIANCE 354 float varVal = 1.0 / variance->kernel[y][x]; 355 i1 *= varVal; 356 i1i1 *= varVal; 357 one *= varVal; 358 i2 *= varVal; 359 i1i2 *= varVal; 360 #endif 361 362 sumI1 += i1; 363 sumI1I1 += i1i1; 364 sum1 += one; 365 sumI2 += i2; 366 sumI1I2 += i1i2; 367 } 368 } 369 matrix1->data.F64[bgIndex][normIndex] = sumI1; 370 matrix1->data.F64[normIndex][bgIndex] = sumI1; 371 matrix1->data.F64[normIndex][normIndex] = sumI1I1; 372 matrix1->data.F64[bgIndex][bgIndex] = sum1; 373 vector1->data.F64[bgIndex] = sumI2; 374 vector1->data.F64[normIndex] = sumI1I2; 375 121 376 return true; 122 377 } 123 378 124 // Calculate the square part of the matrix derived from multiplying convolutions 125 static bool calculateMatrixSquare(psImage *matrix, // Matrix to calculate 126 const psArray *convolutions1, // Convolutions for element 1 127 const psArray *convolutions2, // Convolutions for element 2 128 const psKernel *variance, // Variance image 129 const psImage *polyValues, // Polynomial values 130 int numKernels, // Number of kernel basis functions 131 int spatialOrder, // Order of spatial variation 132 int footprint // Half-size of stamp 379 // Merge dual matrices and vectors into single matrix equation 380 // Have: Aa = Ct.b + d 381 // Have: Ca = Bb + e 382 // Set: F = ( A -Ct ; C -B ) 383 // Set: g = ( a ; b ) 384 // Set: h = ( d ; e ) 385 // So that we combine the above two equations: Fg = h 386 static bool calculateEquationDual(psImage **outMatrix, 387 psVector **outVector, 388 const psImage *sumMatrix1, 389 const psImage *sumMatrix2, 390 const psImage *sumMatrixX, 391 const psVector *sumVector1, 392 const psVector *sumVector2 133 393 ) 134 394 { 135 bool symmetric = (convolutions1 == convolutions2 ? true : false); // Is matrix symmetric? 136 137 for (int i = 0; i < numKernels; i++) { 138 psKernel *iConv = convolutions1->data[i]; // Convolution for i-th element 139 140 for (int j = (symmetric ? i : 0); j < numKernels; j++) { 141 psKernel *jConv = convolutions2->data[j]; // Convolution for j-th element 142 143 if (!calculateMatrixElement2(matrix, i, j, iConv, jConv, variance, polyValues, numKernels, 144 footprint, spatialOrder, symmetric)) { 145 psTrace("psModules.imcombine", 2, "Bad sumCC at %d, %d", i, j); 146 return false; 147 } 395 psAssert(sumMatrix1 && sumMatrix2 && sumMatrixX, "Require input matrices"); 396 psAssert(sumVector1 && sumVector2, "Require input vectors"); 397 int num1 = sumVector1->n; // Number of parameters in first set 398 int num2 = sumVector2->n; // Number of parameters in second set 399 int num = num1 + num2; // Number of parameters in new set 400 401 psAssert(sumMatrix1->type.type == PS_TYPE_F64 && 402 sumMatrix2->type.type == PS_TYPE_F64 && 403 sumMatrixX->type.type == PS_TYPE_F64 && 404 sumVector1->type.type == PS_TYPE_F64 && 405 sumVector2->type.type == PS_TYPE_F64, 406 "Require input type is F64"); 407 408 psAssert(outMatrix, "Require output matrix"); 409 psAssert(outVector, "Require output vector"); 410 if (!*outMatrix) { 411 *outMatrix = psImageAlloc(num, num, PS_TYPE_F64); 412 } 413 if (!*outVector) { 414 *outVector = psVectorAlloc(num, PS_TYPE_F64); 415 } 416 psImage *matrix = *outMatrix; 417 psVector *vector = *outVector; 418 419 psAssert(sumMatrix1->numCols == num1 && sumMatrix1->numRows == num1, "Require size NxN"); 420 psAssert(sumMatrix2->numCols == num2 && sumMatrix2->numRows == num2, "Require size MxM"); 421 psAssert(sumMatrixX->numCols == num1 && sumMatrixX->numRows == num2, "Require size MxN"); 422 423 memcpy(vector->data.F64, sumVector1->data.F64, num1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 424 memcpy(&vector->data.F64[num1], sumVector2->data.F64, num2 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 425 426 for (int i = 0; i < num1; i++) { 427 memcpy(matrix->data.F64[i], sumMatrix1->data.F64[i], num1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 428 for (int j = 0, k = num1; j < num2; j++, k++) { 429 matrix->data.F64[i][k] = - sumMatrixX->data.F64[j][i]; 430 } 431 } 432 for (int i1 = 0, i2 = num1; i1 < num2; i1++, i2++) { 433 memcpy(matrix->data.F64[i2], sumMatrixX->data.F64[i1], num1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 434 for (int j = 0, k = num1; j < num2; j++, k++) { 435 matrix->data.F64[i2][k] = - sumMatrix2->data.F64[i1][j]; 148 436 } 149 437 } … … 152 440 } 153 441 154 // Calculate least-squares matrix and vector155 static bool calculateMatrix(psImage *matrix, // Matrix to calculate156 const pmSubtractionKernels *kernels, // Kernel components157 const psArray *convolutions, // Convolutions of source with kernels158 const psKernel *input, // Input stamp, or NULL159 const psKernel *variance, // Variance stamp160 const psImage *polyValues, // Spatial polynomial values161 int footprint, // (Half-)Size of stamp162 bool normAndBG // Calculate normalisation and background terms?163 )164 {165 int numKernels = kernels->num; // Number of kernel components166 int spatialOrder = kernels->spatialOrder; // Maximum order of spatial variation167 int numSpatial = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of spatial variation terms168 int bgOrder = kernels->bgOrder; // Maximum order of background fit169 int numBackground = normAndBG ? PM_SUBTRACTION_POLYTERMS(bgOrder) : 0; // Number of background terms170 int numTerms = numKernels * numSpatial + (normAndBG ? 1 + numBackground : 0); // Total number of terms171 assert(matrix);172 assert(matrix->numCols == matrix->numRows);173 assert(matrix->numCols == numTerms);174 assert(convolutions && convolutions->n == numKernels);175 assert(polyValues);176 assert(!normAndBG || input); // If we want the normalisation and BG, then we need the input image177 178 // Square part of the matrix (convolution-convolution products)179 if (!calculateMatrixSquare(matrix, convolutions, convolutions, variance, polyValues, numKernels,180 spatialOrder, footprint)) {181 return false;182 }183 184 // XXX To support higher-order background model than simply constant, the below code needs to be updated.185 if (normAndBG) {186 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation187 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background188 189 for (int i = 0; i < numKernels; i++) {190 psKernel *conv = convolutions->data[i]; // Convolution for i-th element191 192 // Normalisation-convolution terms193 if (!calculateMatrixElement1(matrix, i, normIndex, conv, input, variance, polyValues, numKernels,194 footprint, spatialOrder, true)) {195 psTrace("psModules.imcombine", 2, "Bad sumIC at %d", i);196 return false;197 }198 199 // Background-convolution terms200 double sumC = 0.0; // Sum of the convolution201 for (int y = - footprint; y <= footprint; y++) {202 for (int x = - footprint; x <= footprint; x++) {203 double value = conv->kernel[y][x];204 #ifdef USE_VARIANCE205 value /= variance->kernel[y][x];206 #endif207 sumC += value;208 }209 }210 if (!isfinite(sumC)) {211 psTrace("psModules.imcombine", 2, "Bad sumC at %d", i);212 return false;213 }214 215 for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) {216 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) {217 double value = sumC * polyValues->data.F64[yOrder][xOrder];218 matrix->data.F64[index][bgIndex] = value;219 matrix->data.F64[bgIndex][index] = value;220 }221 }222 }223 224 // Background only, normalisation only, and background-normalisation terms225 double sum1 = 0.0; // Sum of the weighting226 double sumI = 0.0; // Sum of the input227 double sumII = 0.0; // Sum of the input squared228 for (int y = - footprint; y <= footprint; y++) {229 for (int x = - footprint; x <= footprint; x++) {230 double invNoise2 = 1.0;231 #ifdef USE_VARIANCE232 invNoise2 /= variance->kernel[y][x];233 #endif234 double value = input->kernel[y][x] * invNoise2;235 sumI += value;236 sumII += value * input->kernel[y][x];237 sum1 += invNoise2;238 }239 }240 if (!isfinite(sumI)) {241 psTrace("psModules.imcombine", 2, "Bad sumI detected");242 return false;243 }244 if (!isfinite(sumII)) {245 psTrace("psModules.imcombine", 2, "Bad sumII detected");246 return false;247 }248 if (!isfinite(sum1)) {249 psTrace("psModules.imcombine", 2, "Bad sum1 detected");250 return false;251 }252 matrix->data.F64[normIndex][normIndex] = sumII;253 matrix->data.F64[bgIndex][bgIndex] = sum1;254 matrix->data.F64[normIndex][bgIndex] = sumI;255 matrix->data.F64[bgIndex][normIndex] = sumI;256 }257 258 return true;259 }260 261 262 // Calculate least-squares matrix and vector263 static bool calculateVector(psVector *vector, // Vector to calculate, or NULL264 const pmSubtractionKernels *kernels, // Kernel components265 const psArray *convolutions, // Convolutions of source with kernels266 const psKernel *input, // Input stamp, or NULL if !normAndBG267 const psKernel *target, // Target stamp268 const psKernel *variance, // Variance stamp269 const psImage *polyValues, // Spatial polynomial values270 int footprint, // (Half-)Size of stamp271 bool normAndBG // Calculate normalisation and background terms?272 )273 {274 int numKernels = kernels->num; // Number of kernel components275 int spatialOrder = kernels->spatialOrder; // Maximum order of spatial variation276 int numSpatial = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of spatial variation terms277 int bgOrder = kernels->bgOrder; // Maximum order of background fit278 int numBackground = normAndBG ? PM_SUBTRACTION_POLYTERMS(bgOrder) : 0; // Number of background terms279 int numTerms = numKernels * numSpatial + (normAndBG ? 1 + numBackground : 0); // Total number of terms280 assert(vector && vector->n == numTerms);281 assert(convolutions && convolutions->n == numKernels);282 assert(target);283 assert(polyValues);284 assert(!normAndBG || input); // If we want the normalisation and BG, then we need the input image285 286 // Convolution terms287 for (int i = 0; i < numKernels; i++) {288 psKernel *conv = convolutions->data[i]; // Convolution for i-th element289 double sumTC = 0.0; // Sum of the target and convolution290 for (int y = - footprint; y <= footprint; y++) {291 for (int x = - footprint; x <= footprint; x++) {292 double value = target->kernel[y][x] * conv->kernel[y][x];293 #ifdef USE_VARIANCE294 value /= variance->kernel[y][x];295 #endif296 sumTC += value;297 }298 }299 if (!isfinite(sumTC)) {300 psTrace("psModules.imcombine", 2, "Bad sumTC at %d", i);301 return false;302 }303 for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) {304 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) {305 vector->data.F64[index] = sumTC * polyValues->data.F64[yOrder][xOrder];306 }307 }308 }309 310 if (normAndBG) {311 // Background terms312 double sumT = 0.0; // Sum of the target313 double sumIT = 0.0; // Sum of the input-target product314 for (int y = - footprint; y <= footprint; y++) {315 for (int x = - footprint; x <= footprint; x++) {316 double value = target->kernel[y][x];317 #ifdef USE_VARIANCE318 value /= variance->kernel[y][x];319 #endif320 sumIT += value * input->kernel[y][x];321 sumT += value;322 }323 }324 if (!isfinite(sumT)) {325 psTrace("psModules.imcombine", 2, "Bad sumI detected");326 return false;327 }328 if (!isfinite(sumIT)) {329 psTrace("psModules.imcombine", 2, "Bad sumIT detected");330 return false;331 }332 333 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation term334 vector->data.F64[normIndex] = sumIT;335 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background term336 vector->data.F64[bgIndex] = sumT;337 }338 339 return true;340 }341 342 343 344 // Calculate the cross-matrix, composed of convolutions of each image345 // Note that the cross-matrix is NOT square346 static bool calculateMatrixCross(psImage *matrix, // Matrix to calculate347 const pmSubtractionKernels *kernels, // Kernel components348 const psArray *convolutions1, // Convolutions of image 1349 const psArray *convolutions2, // Convolutions of image 2350 const psKernel *image1, // Image 1 stamp351 const psKernel *variance, // Variance stamp352 const psImage *polyValues, // Spatial polynomial values353 int footprint // (Half-)Size of stamp354 )355 {356 assert(matrix);357 int numKernels = kernels->num; // Number of kernel components358 int spatialOrder = kernels->spatialOrder; // Maximum order of spatial variation359 int numSpatial = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of spatial polynomial terms360 int numBackground = PM_SUBTRACTION_POLYTERMS(kernels->bgOrder); // Number of background terms361 int numCols = numKernels * numSpatial + 1 + numBackground; // Number of columns362 int numRows = numKernels * numSpatial; // Number of rows363 assert(matrix->numCols == numCols && matrix->numRows == numRows);364 assert(convolutions1 && convolutions1->n == numKernels);365 assert(convolutions2 && convolutions2->n == numKernels);366 367 int normIndex, bgIndex; // Indices in matrix for normalisation and background terms368 PM_SUBTRACTION_INDICES(normIndex, bgIndex, kernels);369 370 if (!calculateMatrixSquare(matrix, convolutions1, convolutions2, variance, polyValues, numKernels,371 spatialOrder, footprint)) {372 return false;373 }374 375 for (int i = 0; i < numKernels; i++) {376 // Normalisation377 psKernel *conv = convolutions2->data[i]; // Convolution378 if (!calculateMatrixElement1(matrix, i, normIndex, conv, image1, variance, polyValues, numKernels,379 footprint, spatialOrder, false)) {380 psTrace("psModules.imcombine", 2, "Bad sumIC at %d", i);381 return false;382 }383 384 // Background385 double sumC = 0.0; // Sum of the weighting386 for (int y = - footprint; y <= footprint; y++) {387 for (int x = - footprint; x <= footprint; x++) {388 double value = conv->kernel[y][x];389 #ifdef USE_VARIANCE390 value /= variance->kernel[y][x];391 #endif392 sumC += value;393 }394 }395 if (!isfinite(sumC)) {396 psTrace("psModules.imcombine", 2, "Bad sumC detected at %d", i);397 return false;398 }399 for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) {400 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) {401 matrix->data.F64[index][bgIndex] = sumC * polyValues->data.F64[yOrder][xOrder];402 }403 }404 }405 406 return true;407 }408 409 442 410 443 // Add in penalty term to least-squares vector 411 static bool calculatePenalty(psVector *vector, // Vector to which to add in penalty term 412 const pmSubtractionKernels *kernels // Kernel parameters 444 static bool calculatePenalty(psImage *matrix, // Matrix to which to add in penalty term 445 psVector *vector, // Vector to which to add in penalty term 446 const pmSubtractionKernels *kernels, // Kernel parameters 447 float norm // Normalisation 413 448 ) 414 449 { … … 423 458 for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) { 424 459 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) { 425 vector->data.F64[index] -= penalties->data.F32[i]; 460 // Contribution to chi^2: a_i^2 P_i 461 matrix->data.F64[index][index] -= norm * penalties->data.F32[i]; 426 462 } 427 463 } … … 582 618 switch (kernels->mode) { 583 619 case PM_SUBTRACTION_MODE_1: 584 status = calculateMatrix(stamp->matrix1, kernels, stamp->convolutions1, stamp->image1, 585 stamp->variance, polyValues, footprint, true); 586 status &= calculateVector(stamp->vector1, kernels, stamp->convolutions1, stamp->image1, 587 stamp->image2, stamp->variance, polyValues, footprint, true); 620 status = calculateMatrixVector(stamp->matrix1, stamp->vector1, stamp->image2, stamp->image1, 621 stamp->variance, stamp->convolutions1, kernels, polyValues, 622 footprint); 588 623 break; 589 624 case PM_SUBTRACTION_MODE_2: 590 status = calculateMatrix(stamp->matrix1, kernels, stamp->convolutions2, stamp->image2, 591 stamp->variance, polyValues, footprint, true); 592 status &= calculateVector(stamp->vector1, kernels, stamp->convolutions2, stamp->image2, 593 stamp->image1, stamp->variance, polyValues, footprint, true); 625 status = calculateMatrixVector(stamp->matrix1, stamp->vector1, stamp->image1, stamp->image2, 626 stamp->variance, stamp->convolutions2, kernels, polyValues, 627 footprint); 594 628 break; 595 629 case PM_SUBTRACTION_MODE_DUAL: … … 604 638 psVectorInit(stamp->vector2, NAN); 605 639 #endif 606 status = calculateMatrix(stamp->matrix1, kernels, stamp->convolutions1, stamp->image1, 607 stamp->variance, polyValues, footprint, true); 608 status &= calculateMatrix(stamp->matrix2, kernels, stamp->convolutions2, NULL, 609 stamp->variance, polyValues, footprint, false); 610 status &= calculateMatrixCross(stamp->matrixX, kernels, stamp->convolutions1, 611 stamp->convolutions2, stamp->image1, stamp->variance, polyValues, 612 footprint); 613 status &= calculateVector(stamp->vector1, kernels, stamp->convolutions1, stamp->image1, 614 stamp->image2, stamp->variance, polyValues, footprint, true); 615 status &= calculateVector(stamp->vector2, kernels, stamp->convolutions2, NULL, 616 stamp->image2, stamp->variance, polyValues, footprint, false); 640 status = calculateDualMatrixVector(stamp->matrix1, stamp->vector1, stamp->matrix2, stamp->vector2, 641 stamp->matrixX, stamp->image1, stamp->image2, stamp->variance, 642 stamp->convolutions1, stamp->convolutions2, kernels, polyValues, 643 footprint); 617 644 break; 618 645 default: … … 629 656 630 657 #ifdef TESTING 631 if (psTraceGetLevel("psModules.imcombine.equation") >= 10){658 { 632 659 psString matrixName = NULL; 633 660 psStringAppend(&matrixName, "matrix1_%d.fits", index); … … 825 852 #endif 826 853 827 calculatePenalty(sumVector, kernels); 854 #if 0 855 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 856 calculatePenalty(sumMatrix, sumVector, kernels, sumMatrix->data.F64[bgIndex][bgIndex]); 857 #endif 828 858 829 859 #ifdef TESTING … … 909 939 } 910 940 } 911 calculatePenalty(sumVector1, kernels); 912 calculatePenalty(sumVector2, kernels); 913 914 // Pure matrix operations 915 916 // A * a = Ct * b + d 917 // C * a = B * b + e 918 // 919 // a = (Ct * Bi * C - A)i (Ct * Bi * e - d) 920 // b = Bi * (C * a - e) 921 psVector *a = psVectorRecycle(kernels->solution1, numParams, PS_TYPE_F64); 922 psVector *b = psVectorRecycle(kernels->solution2, numParams2, PS_TYPE_F64); 923 #ifdef TESTING 924 psVectorInit(a, NAN); 925 psVectorInit(b, NAN); 926 #endif 927 psImage *A = sumMatrix1; 928 psImage *B = sumMatrix2; 929 psImage *C = sumMatrixX; 930 psVector *d = sumVector1; 931 psVector *e = sumVector2; 932 933 assert(a->n == numParams); 934 assert(b->n == numParams2); 935 assert(A->numRows == numParams && A->numCols == numParams); 936 assert(B->numRows == numParams2 && B->numCols == numParams2); 937 assert(C->numRows == numParams2 && C->numCols == numParams); 938 assert(d->n == numParams); 939 assert(e->n == numParams2); 940 941 psImage *Bi = psMatrixInvert(NULL, B, NULL); 942 assert(Bi->numRows == numParams2 && Bi->numCols == numParams2); 943 psImage *Ct = psMatrixTranspose(NULL, C); 944 assert(Ct->numRows == numParams && Ct->numCols == numParams2); 945 946 psImage *BiC = psMatrixMultiply(NULL, Bi, C); 947 assert(BiC->numRows == numParams2 && BiC->numCols == numParams); 948 psImage *CtBi = psMatrixMultiply(NULL, Ct, Bi); 949 assert(CtBi->numRows == numParams && CtBi->numCols == numParams2); 950 951 psImage *CtBiC = psMatrixMultiply(NULL, Ct, BiC); 952 assert(CtBiC->numRows == numParams && CtBiC->numCols == numParams); 953 954 psImage *F = (psImage*)psBinaryOp(NULL, CtBiC, "-", A); 955 assert(F->numRows == numParams && F->numCols == numParams); 956 float det = 0.0; 957 psImage *Fi = psMatrixInvert(NULL, F, &det); 958 assert(Fi->numRows == numParams && Fi->numCols == numParams); 959 psTrace("psModules.imcombine", 4, "Determinant of F: %f\n", det); 960 961 psVector *g = psVectorAlloc(numParams, PS_TYPE_F64); 962 #ifdef TESTING 963 psVectorInit(g, NAN); 964 #endif 965 assert(CtBi->numRows == numParams && CtBi->numCols == numParams2); 966 assert(e->n == numParams2); 967 assert(d->n == numParams); 968 for (int i = 0; i < numParams; i++) { 969 double value = 0.0; 970 for (int j = 0; j < numParams2; j++) { 971 value += CtBi->data.F64[i][j] * e->data.F64[j]; 972 } 973 g->data.F64[i] = value - d->data.F64[i]; 974 } 975 976 assert(Fi->numRows == numParams && Fi->numCols == numParams); 977 assert(g->n == numParams); 978 for (int i = 0; i < numParams; i++) { 979 double value = 0.0; 980 for (int j = 0; j < numParams; j++) { 981 value += Fi->data.F64[i][j] * g->data.F64[j]; 982 } 983 a->data.F64[i] = value; 984 } 985 986 psVector *h = psVectorAlloc(numParams2, PS_TYPE_F64); 987 #ifdef TESTING 988 psVectorInit(h, NAN); 989 #endif 990 assert(C->numRows == numParams2 && C->numCols == numParams); 991 assert(a->n == numParams); 992 assert(e->n == numParams2); 993 for (int i = 0; i < numParams2; i++) { 994 double value = 0.0; 995 for (int j = 0; j < numParams; j++) { 996 value += C->data.F64[i][j] * a->data.F64[j]; 997 } 998 h->data.F64[i] = value - e->data.F64[i]; 999 } 1000 1001 assert(Bi->numRows == numParams2 && Bi->numCols == numParams2); 1002 assert(h->n == numParams2); 1003 for (int i = 0; i < numParams2; i++) { 1004 double value = 0.0; 1005 for (int j = 0; j < numParams2; j++) { 1006 value += Bi->data.F64[i][j] * h->data.F64[j]; 1007 } 1008 b->data.F64[i] = value; 1009 } 1010 1011 1012 #if 0 1013 for (int i = 0; i < numParams; i++) { 1014 double aVal1 = 0.0, bVal1 = 0.0; 1015 for (int j = 0; j < numParams2; j++) { 1016 aVal1 += A->data.F64[i][j] * a->data.F64[j]; 1017 bVal1 += Ct->data.F64[i][j] * b->data.F64[j]; 1018 } 1019 bVal1 += d->data.F64[i]; 1020 for (int j = numParams2; j < numParams; j++) { 1021 aVal1 += A->data.F64[i][j] * a->data.F64[j]; 1022 } 1023 printf("%d: %lf\n", i, aVal1 - bVal1); 1024 } 1025 1026 for (int i = 0; i < numParams2; i++) { 1027 double aVal2 = 0.0, bVal2 = 0.0; 1028 for (int j = 0; j < numParams2; j++) { 1029 aVal2 += C->data.F64[i][j] * a->data.F64[j]; 1030 bVal2 += B->data.F64[i][j] * b->data.F64[j]; 1031 } 1032 bVal2 += e->data.F64[i]; 1033 for (int j = numParams2; j < numParams; j++) { 1034 aVal2 += C->data.F64[i][j] * a->data.F64[j]; 1035 } 1036 printf("%d: %lf\n", i, aVal2 - bVal2); 1037 } 1038 #endif 941 942 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 943 calculatePenalty(sumMatrix1, sumVector1, kernels, sumMatrix1->data.F64[bgIndex][bgIndex]); 944 calculatePenalty(sumMatrix2, sumVector2, kernels, -sumMatrix1->data.F64[bgIndex][bgIndex]); 945 946 psImage *sumMatrix = NULL; // Combined matrix 947 psVector *sumVector = NULL; // Combined vector 948 calculateEquationDual(&sumMatrix, &sumVector, sumMatrix1, sumMatrix2, 949 sumMatrixX, sumVector1, sumVector2); 1039 950 1040 951 #ifdef TESTING 1041 952 { 1042 psFits *fits = psFitsOpen("sumMatrix 1.fits", "w");1043 psFitsWriteImage(fits, NULL, sumMatrix 1, 0, NULL);953 psFits *fits = psFitsOpen("sumMatrix.fits", "w"); 954 psFitsWriteImage(fits, NULL, sumMatrix, 0, NULL); 1044 955 psFitsClose(fits); 1045 956 } 1046 957 { 1047 psFits *fits = psFitsOpen("sumMatrix2.fits", "w"); 1048 psFitsWriteImage(fits, NULL, sumMatrix2, 0, NULL); 958 psImage *image = psImageAlloc(1, numParams + numParams2, PS_TYPE_F64); 959 psFits *fits = psFitsOpen("sumVector.fits", "w"); 960 for (int i = 0; i < numParams + numParams2; i++) { 961 image->data.F64[0][i] = sumVector->data.F64[i]; 962 } 963 psFitsWriteImage(fits, NULL, image, 0, NULL); 964 psFree(image); 1049 965 psFitsClose(fits); 1050 966 } 967 #endif 968 969 psVector *solution = NULL; // Solution to equation! 1051 970 { 1052 psFits *fits = psFitsOpen("sumMatrixX.fits", "w"); 1053 psFitsWriteImage(fits, NULL, sumMatrixX, 0, NULL); 971 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector); 972 if (!solution) { 973 psError(PS_ERR_UNKNOWN, false, "SVD solution of least-squares equation failed.\n"); 974 psFree(sumMatrix); 975 psFree(sumVector); 976 return NULL; 977 } 978 979 int numSpatial = PM_SUBTRACTION_POLYTERMS(kernels->spatialOrder); // Number of spatial variations 980 int numKernels = kernels->num; // Number of kernel basis functions 981 982 // Remove a kernel basis for image 1 from the equation 983 #define MASK_BASIS_1(INDEX) \ 984 { \ 985 for (int j = 0, index = INDEX; j < numSpatial; j++, index += numKernels) { \ 986 for (int k = 0; k < numParams2; k++) { \ 987 sumMatrix1->data.F64[k][index] = 0.0; \ 988 sumMatrix1->data.F64[index][k] = 0.0; \ 989 sumMatrixX->data.F64[k][index] = 0.0; \ 990 } \ 991 sumMatrix1->data.F64[bgIndex][index] = 0.0; \ 992 sumMatrix1->data.F64[index][bgIndex] = 0.0; \ 993 sumMatrix1->data.F64[normIndex][index] = 0.0; \ 994 sumMatrix1->data.F64[index][normIndex] = 0.0; \ 995 sumMatrix1->data.F64[index][index] = 1.0; \ 996 sumVector1->data.F64[index] = 0.0; \ 997 } \ 998 } 999 1000 // Remove a kernel basis for image 2 from the equation 1001 #define MASK_BASIS_2(INDEX) \ 1002 { \ 1003 for (int j = 0, index = INDEX; j < numSpatial; j++, index += numKernels) { \ 1004 for (int k = 0; k < numParams2; k++) { \ 1005 sumMatrix2->data.F64[k][index] = 0.0; \ 1006 sumMatrix2->data.F64[index][k] = 0.0; \ 1007 sumMatrixX->data.F64[index][k] = 0.0; \ 1008 } \ 1009 sumMatrix2->data.F64[index][index] = 1.0; \ 1010 sumMatrixX->data.F64[index][normIndex] = 0.0; \ 1011 sumMatrixX->data.F64[index][bgIndex] = 0.0; \ 1012 sumVector2->data.F64[index] = 0.0; \ 1013 } \ 1014 } 1015 1016 #define TOL 1.0e-5 1017 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1018 double norm = solution->data.F64[normIndex]; // Normalisation 1019 double thresh = norm * TOL; // Threshold for low parameters 1020 for (int i = 0; i < numKernels; i++) { 1021 // Getting 0th order parameter value. In the presence of spatial variation, the actual value 1022 // of the parameter will vary over the image. We are in effect getting the value in the 1023 // centre of the image. If we use different polynomial functions (e.g., Chebyshev), we may 1024 // have to change this to properly determine the value of the parameter at the centre. 1025 double param1 = solution->data.F64[i], 1026 param2 = solution->data.F64[numParams + i]; // Parameters of interest 1027 bool mask1 = false, mask2 = false; // Masked the parameter? 1028 if (fabs(param1) < thresh) { 1029 psTrace("psModules.imcombine", 7, "Parameter %d: 1 below threshold\n", i); 1030 MASK_BASIS_1(i); 1031 mask1 = true; 1032 } 1033 if (fabs(param2) < thresh) { 1034 psTrace("psModules.imcombine", 7, "Parameter %d: 2 below threshold\n", i); 1035 MASK_BASIS_2(i); 1036 mask2 = true; 1037 } 1038 1039 if (!mask1 && !mask2) { 1040 if (fabs(param1) < fabs(param2)) { 1041 psTrace("psModules.imcombine", 7, "Parameter %d: 1 < 2\n", i); 1042 MASK_BASIS_1(i); 1043 } else { 1044 psTrace("psModules.imcombine", 7, "Parameter %d: 2 < 1\n", i); 1045 MASK_BASIS_2(i); 1046 } 1047 } 1048 } 1049 } 1050 1051 calculateEquationDual(&sumMatrix, &sumVector, sumMatrix1, sumMatrix2, 1052 sumMatrixX, sumVector1, sumVector2); 1053 1054 #ifdef TESTING 1055 { 1056 psFits *fits = psFitsOpen("sumMatrixFix.fits", "w"); 1057 psFitsWriteImage(fits, NULL, sumMatrix, 0, NULL); 1054 1058 psFitsClose(fits); 1055 1059 } 1056 1060 { 1057 psFits *fits = psFitsOpen("sumFinverse.fits", "w"); 1058 psFitsWriteImage(fits, NULL, Fi, 0, NULL); 1061 psImage *image = psImageAlloc(1, numParams + numParams2, PS_TYPE_F64); 1062 psFits *fits = psFitsOpen("sumVectorFix.fits", "w"); 1063 for (int i = 0; i < numParams + numParams2; i++) { 1064 image->data.F64[0][i] = sumVector->data.F64[i]; 1065 } 1066 psFitsWriteImage(fits, NULL, image, 0, NULL); 1067 psFree(image); 1059 1068 psFitsClose(fits); 1060 1069 } 1061 1070 #endif 1062 1071 1063 kernels->solution1 = a; 1064 kernels->solution2 = b; 1065 1066 // XXXXX Free temporary matrices and vectors 1072 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector); 1073 if (!solution) { 1074 psError(PS_ERR_UNKNOWN, false, "SVD solution of least-squares equation failed.\n"); 1075 psFree(sumMatrix); 1076 psFree(sumVector); 1077 return NULL; 1078 } 1079 1080 psFree(sumMatrix1); 1081 psFree(sumMatrix2); 1082 psFree(sumMatrixX); 1083 psFree(sumVector1); 1084 psFree(sumVector2); 1085 1086 psFree(sumMatrix); 1087 psFree(sumVector); 1088 1089 #ifdef TESTING 1090 { 1091 psImage *image = psImageAlloc(1, numParams + numParams2, PS_TYPE_F64); 1092 psFits *fits = psFitsOpen("solnVector.fits", "w"); 1093 for (int i = 0; i < numParams + numParams2; i++) { 1094 image->data.F64[0][i] = solution->data.F64[i]; 1095 } 1096 psFitsWriteImage(fits, NULL, image, 0, NULL); 1097 psFree(image); 1098 psFitsClose(fits); 1099 } 1100 #endif 1101 1102 if (!kernels->solution1) { 1103 kernels->solution1 = psVectorAlloc(numParams, PS_TYPE_F64); 1104 } 1105 if (!kernels->solution2) { 1106 kernels->solution2 = psVectorAlloc(numParams2, PS_TYPE_F64); 1107 } 1108 1109 memcpy(kernels->solution1->data.F64, solution->data.F64, numParams * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1110 memcpy(kernels->solution2->data.F64, &solution->data.F64[numParams], 1111 numParams2 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1112 1113 psFree(solution); 1067 1114 1068 1115 }
Note:
See TracChangeset
for help on using the changeset viewer.
