Changeset 26373
- Timestamp:
- Dec 8, 2009, 7:11:00 PM (16 years ago)
- Location:
- branches/eam_branches/20091201/psModules/src/imcombine
- Files:
-
- 4 edited
-
pmSubtraction.c (modified) (2 diffs)
-
pmSubtractionEquation.c (modified) (9 diffs)
-
pmSubtractionStamps.c (modified) (2 diffs)
-
pmSubtractionVisual.c (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/20091201/psModules/src/imcombine/pmSubtraction.c
r26332 r26373 21 21 #include "pmSubtractionStamps.h" 22 22 #include "pmSubtractionEquation.h" 23 #include "pmSubtractionVisual.h" 23 24 #include "pmSubtractionThreads.h" 24 25 … … 525 526 int x0 = - image->xMin, y0 = - image->yMin; // Position of centre of convolved image 526 527 psKernel *convolved = psKernelAllocFromImage(conv, x0, y0); // Kernel version 528 529 // pmSubtractionVisualShowSubtraction(image->image, kernel->image, conv); 530 527 531 psFree(conv); 528 532 return convolved; -
branches/eam_branches/20091201/psModules/src/imcombine/pmSubtractionEquation.c
r26347 r26373 831 831 } 832 832 833 // private functions used on pmSubtractionSolveEquation 834 bool psVectorWriteFile (char *filename, const psVector *vector); 835 bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header); 836 837 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U); 838 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt); 839 840 psVector *p_pmSubSolve_UtB (psImage *U, psVector *B); 841 psVector *p_pmSubSolve_wUtB (psVector *w, psVector *UtB); 842 psVector *p_pmSubSolve_VwUtB (psImage *V, psVector *wUtB); 843 844 psVector *p_pmSubSolve_Ax (psImage *A, psVector *x); 845 846 double p_pmSubSolve_y2 (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps); 847 double p_pmSubSolve_VdV (psVector *x, psVector *y); 848 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps); 849 833 850 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, 834 851 const pmSubtractionStampList *stamps, … … 943 960 { 944 961 psImage *inverse = psMatrixInvert(NULL, sumMatrix, NULL); 945 psFits *fits = psFitsOpen("matrixInv.fits", "w"); 946 psFitsWriteImage(fits, NULL, inverse, 0, NULL); 947 psFitsClose(fits); 962 psFitsWriteImageSimple("matrixInv.fits", inverse, NULL); 948 963 psFree(inverse); 949 964 } … … 952 967 psImage *Xt = psMatrixTranspose(NULL, X); 953 968 psImage *XtX = psMatrixMultiply(NULL, Xt, X); 954 psFits *fits = psFitsOpen("matrixErr.fits", "w"); 955 psFitsWriteImage(fits, NULL, XtX, 0, NULL); 956 psFitsClose(fits); 969 psFitsWriteImageSimple("matrixErr.fits", XtX, NULL); 957 970 psFree(X); 958 971 psFree(Xt); … … 961 974 #endif 962 975 963 // XXX test: save the matrix A and vector b:964 {965 psFits *fits = psFitsOpen("matrix.fits", "w");966 psFitsWriteImage(fits, NULL, sumMatrix, 0, NULL);967 psFitsClose(fits);968 969 FILE *f = fopen ("vector.dat", "w");970 int fd = fileno(f);971 p_psVectorPrint (fd, sumVector, "B");972 fclose (f);973 }974 975 976 # define SVD_ANALYSIS 1 976 // re-do this section with SVD: 977 # define COEFF_SIG 0.0 978 # define SVD_TOL 1e-9 979 980 psVector *solution = NULL; 981 psVector *solutionErr = NULL; 982 983 // Use SVD to determine the kernel coeffs (and validate) 977 984 if (SVD_ANALYSIS) { 978 // We have sumVector and sumMatrix. we are trying to solve the equation: sumMatrix * x = sumVector. 985 986 // We have sumVector and sumMatrix. we are trying to solve the following equation: 987 // sumMatrix * x = sumVector. 988 979 989 // we can use any standard matrix inversion to solve this. However, the basis 980 990 // functions in general have substantial correlation, so that the solution may be 981 // somewhat poorly determi end or unstable. If not numerically ill-conditioned, the991 // somewhat poorly determined or unstable. If not numerically ill-conditioned, the 982 992 // system of equations may be statistically ill-conditioned. Noise in the image 983 // will drive insignificant but correlatedterms in the solution. To avoid these993 // will drive insignificant, but correlated, terms in the solution. To avoid these 984 994 // problems, we can use SVD to identify numerically unconstrained values and to 985 995 // avoid statistically badly determined value. … … 993 1003 // identify the elements of x that are insignificant (x / dx < 1.0? < 0.5?) -> set to 0.0 994 1004 995 // I get confused by the index values between the image vs matrix usage: In terms 996 // of the elements of an image A(x,y) = A->data.F32[y][x] = A_x,y, a matrix 997 // multiplication is: A_k,j * B_i,k = C_i,j 1005 // XXX TEST with known matrix: 1006 // psFree (sumMatrix); 1007 // sumMatrix = psImageAlloc (2, 2, PS_TYPE_F64); 1008 // sumMatrix->data.F64[0][0] = 1.0; 1009 // sumMatrix->data.F64[0][1] = 0.5; 1010 // 1011 // sumMatrix->data.F64[1][0] = 0.5; 1012 // sumMatrix->data.F64[1][1] = 2.0; 1013 1014 // sumMatrix->data.F64[2][0] = 0.0; 1015 // sumMatrix->data.F64[2][1] = 1.0; 1016 1017 // TEST psFitsWriteImageSimple("A.fits", sumMatrix, NULL); 1018 // TEST psVectorWriteFile("B.dat", sumVector);; 1019 1020 // If I use the SVD trick to re-condition the matrix, I need to break out the 1021 // kernel terms from the normalization and background terms. 1022 1023 // XX int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1024 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 1025 1026 // solve for the normalization first (independent of all other terms) 1027 // XX double sumRR = sumMatrix->data.F64[normIndex][normIndex]; 1028 // XX double sumIR = sumVector->data.F64[normIndex]; 1029 // XX double norm = sumIR / sumRR; 1030 1031 // now pull out the kernel elements into their own square matrix 1032 psImage *kernelMatrix = psImageAlloc (sumMatrix->numCols - 1, sumMatrix->numRows - 1, PS_TYPE_F64); 1033 psVector *kernelVector = psVectorAlloc (sumMatrix->numCols - 1, PS_TYPE_F64); 1034 1035 // note that we need to subtract norm*sumRC from the sumVector elements (since we 1036 // are fitting to the residual image of I - norm*Ref) 1037 for (int ix = 0, kx = 0; ix < sumMatrix->numCols; ix++) { 1038 // if (ix == normIndex) continue; 1039 if (ix == bgIndex) continue; 1040 for (int iy = 0, ky = 0; iy < sumMatrix->numRows; iy++) { 1041 // if (iy == normIndex) continue; 1042 if (iy == bgIndex) continue; 1043 kernelMatrix->data.F64[ky][kx] = sumMatrix->data.F64[iy][ix]; 1044 ky++; 1045 } 1046 // kernelVector->data.F64[kx] = sumVector->data.F64[ix] - norm*sumMatrix->data.F64[normIndex][ix]; 1047 kernelVector->data.F64[kx] = sumVector->data.F64[ix]; 1048 kx++; 1049 } 1050 1051 psFitsWriteImageSimple("A.fits", kernelMatrix, NULL); 998 1052 999 1053 psImage *U = NULL; 1000 1054 psImage *V = NULL; 1001 1055 psVector *w = NULL; 1002 if (!psMatrixSVD (&U, &w, &V, sumMatrix)) {1056 if (!psMatrixSVD (&U, &w, &V, kernelMatrix)) { 1003 1057 psError(PS_ERR_UNKNOWN, false, "failed to perform SVD on sumMatrix\n"); 1004 1058 return NULL; 1005 1059 } 1006 1060 1007 // calculate A_inverse and x_svd 1008 // A'_i,j = \sum_k (V_k,j * w_k * Ut_i,k) 1009 // but U^T_i,j = U_j,i, so: 1010 // A'_i,j = \sum_k (V_k,j * w_k * U_k,i) 1011 1012 // v1_j = \sum_k (UT_k,j * B_k) 1013 // v1_j = w_j * \sum_k (U_j,k * B_k) 1014 // x_i = \sum_j V_j,i * w_j * \sum_k (U_j,k * B_k) 1015 1016 // A'_i,j = \sum_k (V_k,j * w_k * U_k,i) 1017 1018 psImage *Ainv = psImageAlloc(A->numCols, A->numRows, PS_TYPE_F32); 1019 psVector *Xsvd = psVectorAlloc(A->numCols, PS_TYPE_F32); 1020 for (int iy = 0; iy < A->numRows; iy++) { 1021 double vsum = 0.0; 1022 for (int ix = 0; ix < A->numCols; ix++) { 1023 double msum = 0.0; 1024 double vsum1 = 0.0; 1025 for (int k = 0; k < A->numCols; k++) { 1026 if (fabs(w->data.F32[k]) < FLT_EPSILON) continue; 1027 msum += V->data.F32[iy][k] * U->data.F32[ix][k] / w->data.F32[k]; 1028 vsum1 += U->data.F32[k][iy] * B->data.F32[k]; 1029 } 1030 Ainv->data.F32[iy][ix] = sum; 1031 if (fabs(w->data.F32[ix]) < FLT_EPSILON) continue; 1032 vsum += V->data.F32[iy][ix] * vsum1 / w->data.F32[ix]; 1033 } 1034 Xsvd->data.F32[iy] = vsum; 1035 } 1036 1037 // compare Xsvd[k] to dXsvd and zero out w entries that are not significant 1038 # define COEFF_SIG 1.0 1039 for (int k = 0; k < A->numRows; k++) { 1040 float dXsvd = sqrt(Ainv->data.F32[k][k]); 1041 if (fabs(Xsvd->data.F32[k] / dXsvd) < COEFF_SIG) { 1042 w->data.F32[k] = 0.0; 1043 } 1044 } 1045 1046 // 1047 1048 1049 } 1050 1051 psVector *permutation = NULL; // Permutation vector, required for LU decomposition 1052 psImage *luMatrix = psMatrixLUDecomposition(NULL, &permutation, sumMatrix); 1053 psFree(sumMatrix); 1054 if (!luMatrix) { 1055 psError(PS_ERR_UNKNOWN, true, "LU Decomposition of least-squares matrix failed.\n"); 1056 psFree(sumVector); 1057 psFree(luMatrix); 1058 psFree(permutation); 1059 return NULL; 1060 } 1061 1062 psVector *solution = psMatrixLUSolution(NULL, luMatrix, sumVector, permutation); 1063 psFree(sumVector); 1064 psFree(luMatrix); 1065 psFree(permutation); 1066 if (!solution) { 1067 psError(PS_ERR_UNKNOWN, true, "Failed to solve the least-squares system.\n"); 1068 return NULL; 1069 } 1061 // TEST psFitsWriteImageSimple("U.fits", U, NULL); 1062 // TEST psFitsWriteImageSimple("V.fits", V, NULL); 1063 // TEST psVectorWriteFile("w.dat", w); 1064 1065 // calculate A_inverse: 1066 // Ainv = V * w * U^T 1067 psImage *wUt = p_pmSubSolve_wUt (w, U); 1068 psImage *Ainv = p_pmSubSolve_VwUt (V, wUt); 1069 1070 // TEST psFitsWriteImageSimple("AInv.fits", Ainv, NULL); 1071 // TEST psImage *Io = p_pmSubSolve_VwUt (Ainv, sumMatrix); 1072 // TEST psFitsWriteImageSimple("I.fits", Io, NULL); 1073 1074 // kernel terms: 1075 for (int i = 0; i < w->n; i++) { 1076 fprintf (stderr, "w: %f\n", w->data.F64[i]); 1077 } 1078 1079 // XXX loop over w adding in more and more of the values until chisquare is no 1080 // longer dropping significantly 1081 1082 // zero-out ill-conditioned SVD components: 1083 // largest w value is in w->data.F64[0]: 1084 double Wmax = w->data.F64[0]; 1085 for (int k = 1; k < w->n; k++) { 1086 if (fabs(w->data.F64[k] / Wmax) < SVD_TOL) { 1087 fprintf (stderr, "masking basis function %d : %f\n", k, w->data.F64[k] / Wmax); 1088 w->data.F64[k] = NAN; 1089 psTrace("psModules.imcombine", 5, "masking basis function %d : %f", k, w->data.F64[k] / Wmax); 1090 } 1091 } 1092 1093 // solve for x: 1094 // x = V * w * (U^T * B) 1095 psVector *UtB = p_pmSubSolve_UtB (U, kernelVector); 1096 psVector *wUtB = p_pmSubSolve_wUtB (w, UtB); 1097 psVector *Xsvd = p_pmSubSolve_VwUtB (V, wUtB); 1098 1099 // chi-square for this system of equations: 1100 // chi-square = sum over terms of: (Ax - B)*x - b*x - y^2 1101 // y^2 = \sum_stamps \sum_pixels input->kernel[y][x]^2 1102 psVector *Ax = p_pmSubSolve_Ax (kernelMatrix, Xsvd); 1103 double Axx = p_pmSubSolve_VdV (Ax, Xsvd); 1104 double Bx = p_pmSubSolve_VdV (kernelVector, Xsvd); 1105 double y2 = p_pmSubSolve_y2 (kernels, stamps); 1106 1107 // apparently, this works (compare with the brute force value below 1108 double chiSquare = Axx - 2.0*Bx + y2; 1109 fprintf (stderr, "chi square = %f\n", chiSquare); 1110 1111 // copy the kernel solutions to the full solution vector: 1112 solution = psVectorAlloc(sumVector->n, PS_TYPE_F64); 1113 solutionErr = psVectorAlloc(sumVector->n, PS_TYPE_F64); 1114 1115 for (int ix = 0, kx = 0; ix < sumVector->n; ix++) { 1116 // XX if (ix == normIndex) { 1117 // XX // solution->data.F64[ix] = norm; // 1118 // XX solution->data.F64[ix] = 1.0; // XXX a CHEAT 1119 // XX solutionErr->data.F64[ix] = 0.001; 1120 // XX continue; 1121 // XX } 1122 if (ix == bgIndex) { 1123 solution->data.F64[ix] = 0; 1124 solutionErr->data.F64[ix] = 0.001; 1125 continue; 1126 } 1127 solutionErr->data.F64[ix] = sqrt(Ainv->data.F64[kx][kx]); 1128 solution->data.F64[ix] = Xsvd->data.F64[kx]; 1129 kx++; 1130 } 1131 1132 // TEST psVectorWriteFile("X.dat", Xsvd); 1133 // TEST psVector *Bo = p_pmSubSolve_Ax (sumMatrix, Xsvd); 1134 // TEST psVectorWriteFile("Bo.dat", Bo); 1135 1136 psFree (kernelMatrix); 1137 psFree (kernelVector); 1138 1139 psFree (U); 1140 psFree (V); 1141 psFree (w); 1142 1143 psFree (wUt); 1144 psFree (Ainv); 1145 1146 psFree (UtB); 1147 psFree (wUtB); 1148 psFree (Xsvd); 1149 } else { 1150 psVector *permutation = NULL; // Permutation vector, required for LU decomposition 1151 psImage *luMatrix = psMatrixLUDecomposition(NULL, &permutation, sumMatrix); 1152 psFree(sumMatrix); 1153 if (!luMatrix) { 1154 psError(PS_ERR_UNKNOWN, true, "LU Decomposition of least-squares matrix failed.\n"); 1155 psFree(sumVector); 1156 psFree(luMatrix); 1157 psFree(permutation); 1158 return NULL; 1159 } 1160 1161 solution = psMatrixLUSolution(NULL, luMatrix, sumVector, permutation); 1162 psFree(sumVector); 1163 psFree(luMatrix); 1164 psFree(permutation); 1165 if (!solution) { 1166 psError(PS_ERR_UNKNOWN, true, "Failed to solve the least-squares system.\n"); 1167 return NULL; 1168 } 1169 } 1070 1170 1071 1171 if (!kernels->solution1) { … … 1088 1188 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 1089 1189 for (int i = 0; i < numKernels * numPoly; i++) { 1090 kernels->solution1->data.F64[i] = solution->data.F64[i]; 1091 } 1092 } 1190 fprintf (stderr, "%f +/- %f (%f) -> ", solution->data.F64[i], solutionErr->data.F64[i], fabs(solution->data.F64[i]/solutionErr->data.F64[i])); 1191 if (fabs(solution->data.F64[i] / solutionErr->data.F64[i]) < COEFF_SIG) { 1192 fprintf (stderr, "drop\n"); 1193 kernels->solution1->data.F64[i] = 0.0; 1194 } else { 1195 fprintf (stderr, "keep\n"); 1196 kernels->solution1->data.F64[i] = solution->data.F64[i]; 1197 } 1198 } 1199 } 1200 // double chiSquare = p_pmSubSolve_ChiSquare (kernels, stamps); 1201 // fprintf (stderr, "chi square Brute = %f\n", chiSquare); 1202 1093 1203 psFree (solution); 1094 1204 … … 1141 1251 1142 1252 #ifdef TESTING 1143 { 1144 psFits *fits = psFitsOpen("sumMatrix.fits", "w"); 1145 psFitsWriteImage(fits, NULL, sumMatrix, 0, NULL); 1146 psFitsClose(fits); 1147 } 1253 psFitsWriteImageSimple ("sumMatrix.fits", sumMatrix, NULL); 1148 1254 { 1149 1255 psImage *image = psImageAlloc(1, numParams + numParams2, PS_TYPE_F64); … … 1345 1451 1346 1452 for (int i = 0; i < stamps->num; i++) { 1347 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest1348 if (stamp->status != PM_SUBTRACTION_STAMP_USED) {1349 deviations->data.F32[i] = NAN;1350 continue;1351 }1352 1353 // Calculate coefficients of the kernel basis functions1354 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm);1355 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation1356 double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background1357 1358 // Calculate residuals1359 psKernel *weight = stamp->weight; // Weight postage stamp1360 psImageInit(residual->image, 0.0);1361 if (kernels->mode != PM_SUBTRACTION_MODE_DUAL) {1362 psKernel *target; // Target postage stamp1363 psKernel *source; // Source postage stamp1364 psArray *convolutions; // Convolution postage stamps for each kernel basis function1365 switch (kernels->mode) {1366 case PM_SUBTRACTION_MODE_1:1367 target = stamp->image2;1368 source = stamp->image1;1369 convolutions = stamp->convolutions1;1370 1371 // Having convolved image1 and changed its normalisation, we need to renormalise the residual1372 // so that it is on the scale of image1.1373 psImage *image = pmSubtractionKernelImage(kernels, stamp->xNorm, stamp->yNorm,1374 false); // Kernel image1375 if (!image) {1376 psError(PS_ERR_UNKNOWN, false, "Unable to generate image of kernel.");1377 return false;1378 }1379 double sumKernel = 0; // Sum of kernel, for normalising residual1380 int size = kernels->size; // Half-size of kernel1381 int fullSize = 2 * size + 1; // Full size of kernel1382 for (int y = 0; y < fullSize; y++) {1383 for (int x = 0; x < fullSize; x++) {1384 sumKernel += image->data.F32[y][x];1385 }1386 }1387 psFree(image);1388 devNorm = 1.0 / sumKernel / numPixels;1389 break;1390 case PM_SUBTRACTION_MODE_2:1391 target = stamp->image1;1392 source = stamp->image2;1393 convolutions = stamp->convolutions2;1394 break;1395 default:1396 psAbort("Unsupported subtraction mode: %x", kernels->mode);1397 }1398 1399 for (int j = 0; j < numKernels; j++) {1400 psKernel *convolution = convolutions->data[j]; // Convolution1401 double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j,1402 false); // Coefficient1403 for (int y = - footprint; y <= footprint; y++) {1404 for (int x = - footprint; x <= footprint; x++) {1405 residual->kernel[y][x] -= convolution->kernel[y][x] * coefficient;1406 }1407 }1408 }1453 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest 1454 if (stamp->status != PM_SUBTRACTION_STAMP_USED) { 1455 deviations->data.F32[i] = NAN; 1456 continue; 1457 } 1458 1459 // Calculate coefficients of the kernel basis functions 1460 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm); 1461 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation 1462 double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background 1463 1464 // Calculate residuals 1465 psKernel *weight = stamp->weight; // Weight postage stamp 1466 psImageInit(residual->image, 0.0); 1467 if (kernels->mode != PM_SUBTRACTION_MODE_DUAL) { 1468 psKernel *target; // Target postage stamp 1469 psKernel *source; // Source postage stamp 1470 psArray *convolutions; // Convolution postage stamps for each kernel basis function 1471 switch (kernels->mode) { 1472 case PM_SUBTRACTION_MODE_1: 1473 target = stamp->image2; 1474 source = stamp->image1; 1475 convolutions = stamp->convolutions1; 1476 1477 // Having convolved image1 and changed its normalisation, we need to renormalise the residual 1478 // so that it is on the scale of image1. 1479 psImage *image = pmSubtractionKernelImage(kernels, stamp->xNorm, stamp->yNorm, 1480 false); // Kernel image 1481 if (!image) { 1482 psError(PS_ERR_UNKNOWN, false, "Unable to generate image of kernel."); 1483 return false; 1484 } 1485 double sumKernel = 0; // Sum of kernel, for normalising residual 1486 int size = kernels->size; // Half-size of kernel 1487 int fullSize = 2 * size + 1; // Full size of kernel 1488 for (int y = 0; y < fullSize; y++) { 1489 for (int x = 0; x < fullSize; x++) { 1490 sumKernel += image->data.F32[y][x]; 1491 } 1492 } 1493 psFree(image); 1494 devNorm = 1.0 / sumKernel / numPixels; 1495 break; 1496 case PM_SUBTRACTION_MODE_2: 1497 target = stamp->image1; 1498 source = stamp->image2; 1499 convolutions = stamp->convolutions2; 1500 break; 1501 default: 1502 psAbort("Unsupported subtraction mode: %x", kernels->mode); 1503 } 1504 1505 for (int j = 0; j < numKernels; j++) { 1506 psKernel *convolution = convolutions->data[j]; // Convolution 1507 double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, 1508 false); // Coefficient 1509 for (int y = - footprint; y <= footprint; y++) { 1510 for (int x = - footprint; x <= footprint; x++) { 1511 residual->kernel[y][x] -= convolution->kernel[y][x] * coefficient; 1512 } 1513 } 1514 } 1409 1515 1410 1516 // XXX visualize the target, source, convolution and residual 1411 1517 pmSubtractionVisualShowFitAddStamp (target, source, residual, background, norm, i); 1412 1518 1413 for (int y = - footprint; y <= footprint; y++) {1414 for (int x = - footprint; x <= footprint; x++) {1415 residual->kernel[y][x] += target->kernel[y][x] - background - source->kernel[y][x] * norm;1416 }1417 }1418 } else {1419 // Dual convolution1420 psArray *convolutions1 = stamp->convolutions1; // Convolutions of the first image1421 psArray *convolutions2 = stamp->convolutions2; // Convolutions of the second image1422 psKernel *image1 = stamp->image1; // The first image1423 psKernel *image2 = stamp->image2; // The second image1424 1425 for (int j = 0; j < numKernels; j++) {1426 psKernel *conv1 = convolutions1->data[j]; // Convolution of first image1427 psKernel *conv2 = convolutions2->data[j]; // Convolution of second image1428 double coeff1 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 11429 double coeff2 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, true); // Coefficient 21430 1431 for (int y = - footprint; y <= footprint; y++) {1432 for (int x = - footprint; x <= footprint; x++) {1433 residual->kernel[y][x] += conv2->kernel[y][x] * coeff2 - conv1->kernel[y][x] * coeff1;1434 }1435 }1436 }1437 for (int y = - footprint; y <= footprint; y++) {1438 for (int x = - footprint; x <= footprint; x++) {1439 residual->kernel[y][x] += image2->kernel[y][x] - background - image1->kernel[y][x] * norm;1440 }1441 }1442 }1443 1444 double deviation = 0.0; // Sum of differences1445 for (int y = - footprint; y <= footprint; y++) {1446 for (int x = - footprint; x <= footprint; x++) {1447 double dev = PS_SQR(residual->kernel[y][x]) * weight->kernel[y][x];1448 deviation += dev;1519 for (int y = - footprint; y <= footprint; y++) { 1520 for (int x = - footprint; x <= footprint; x++) { 1521 residual->kernel[y][x] += target->kernel[y][x] - background - source->kernel[y][x] * norm; 1522 } 1523 } 1524 } else { 1525 // Dual convolution 1526 psArray *convolutions1 = stamp->convolutions1; // Convolutions of the first image 1527 psArray *convolutions2 = stamp->convolutions2; // Convolutions of the second image 1528 psKernel *image1 = stamp->image1; // The first image 1529 psKernel *image2 = stamp->image2; // The second image 1530 1531 for (int j = 0; j < numKernels; j++) { 1532 psKernel *conv1 = convolutions1->data[j]; // Convolution of first image 1533 psKernel *conv2 = convolutions2->data[j]; // Convolution of second image 1534 double coeff1 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 1 1535 double coeff2 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, true); // Coefficient 2 1536 1537 for (int y = - footprint; y <= footprint; y++) { 1538 for (int x = - footprint; x <= footprint; x++) { 1539 residual->kernel[y][x] += conv2->kernel[y][x] * coeff2 - conv1->kernel[y][x] * coeff1; 1540 } 1541 } 1542 } 1543 for (int y = - footprint; y <= footprint; y++) { 1544 for (int x = - footprint; x <= footprint; x++) { 1545 residual->kernel[y][x] += image2->kernel[y][x] - background - image1->kernel[y][x] * norm; 1546 } 1547 } 1548 } 1549 1550 double deviation = 0.0; // Sum of differences 1551 for (int y = - footprint; y <= footprint; y++) { 1552 for (int x = - footprint; x <= footprint; x++) { 1553 double dev = PS_SQR(residual->kernel[y][x]) * weight->kernel[y][x]; 1554 deviation += dev; 1449 1555 #ifdef TESTING 1450 residual->kernel[y][x] = dev;1451 #endif 1452 }1453 }1454 deviations->data.F32[i] = devNorm * deviation;1455 psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d): %f\n",1456 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5), deviations->data.F32[i]);1457 if (!isfinite(deviations->data.F32[i])) {1458 stamp->status = PM_SUBTRACTION_STAMP_REJECTED;1459 psTrace("psModules.imcombine", 5,1460 "Rejecting stamp %d (%d,%d) because of non-finite deviation\n",1461 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5));1462 continue;1463 }1556 residual->kernel[y][x] = dev; 1557 #endif 1558 } 1559 } 1560 deviations->data.F32[i] = devNorm * deviation; 1561 psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d): %f\n", 1562 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5), deviations->data.F32[i]); 1563 if (!isfinite(deviations->data.F32[i])) { 1564 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 1565 psTrace("psModules.imcombine", 5, 1566 "Rejecting stamp %d (%d,%d) because of non-finite deviation\n", 1567 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5)); 1568 continue; 1569 } 1464 1570 1465 1571 #ifdef TESTING 1466 {1467 psString filename = NULL;1468 psStringAppend(&filename, "resid_%03d.fits", i);1469 psFits *fits = psFitsOpen(filename, "w");1470 psFree(filename);1471 psFitsWriteImage(fits, NULL, residual->image, 0, NULL);1472 psFitsClose(fits);1473 }1474 if (stamp->image1) {1475 psString filename = NULL;1476 psStringAppend(&filename, "stamp_image1_%03d.fits", i);1477 psFits *fits = psFitsOpen(filename, "w");1478 psFree(filename);1479 psFitsWriteImage(fits, NULL, stamp->image1->image, 0, NULL);1480 psFitsClose(fits);1481 }1482 if (stamp->image2) {1483 psString filename = NULL;1484 psStringAppend(&filename, "stamp_image2_%03d.fits", i);1485 psFits *fits = psFitsOpen(filename, "w");1486 psFree(filename);1487 psFitsWriteImage(fits, NULL, stamp->image2->image, 0, NULL);1488 psFitsClose(fits);1489 }1490 if (stamp->weight) {1491 psString filename = NULL;1492 psStringAppend(&filename, "stamp_weight_%03d.fits", i);1493 psFits *fits = psFitsOpen(filename, "w");1494 psFree(filename);1495 psFitsWriteImage(fits, NULL, stamp->weight->image, 0, NULL);1496 psFitsClose(fits);1497 }1572 { 1573 psString filename = NULL; 1574 psStringAppend(&filename, "resid_%03d.fits", i); 1575 psFits *fits = psFitsOpen(filename, "w"); 1576 psFree(filename); 1577 psFitsWriteImage(fits, NULL, residual->image, 0, NULL); 1578 psFitsClose(fits); 1579 } 1580 if (stamp->image1) { 1581 psString filename = NULL; 1582 psStringAppend(&filename, "stamp_image1_%03d.fits", i); 1583 psFits *fits = psFitsOpen(filename, "w"); 1584 psFree(filename); 1585 psFitsWriteImage(fits, NULL, stamp->image1->image, 0, NULL); 1586 psFitsClose(fits); 1587 } 1588 if (stamp->image2) { 1589 psString filename = NULL; 1590 psStringAppend(&filename, "stamp_image2_%03d.fits", i); 1591 psFits *fits = psFitsOpen(filename, "w"); 1592 psFree(filename); 1593 psFitsWriteImage(fits, NULL, stamp->image2->image, 0, NULL); 1594 psFitsClose(fits); 1595 } 1596 if (stamp->weight) { 1597 psString filename = NULL; 1598 psStringAppend(&filename, "stamp_weight_%03d.fits", i); 1599 psFits *fits = psFitsOpen(filename, "w"); 1600 psFree(filename); 1601 psFitsWriteImage(fits, NULL, stamp->weight->image, 0, NULL); 1602 psFitsClose(fits); 1603 } 1498 1604 #endif 1499 1605 … … 1516 1622 return deviations; 1517 1623 } 1624 1625 // we are supplied U, not Ut; w represents a diagonal matrix (also, we apply 1/w instead of w) 1626 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U) { 1627 1628 psAssert (w->n == U->numCols, "w and U dimensions do not match"); 1629 1630 // wUt has dimensions transposed relative to Ut. 1631 psImage *wUt = psImageAlloc (U->numRows, U->numCols, PS_TYPE_F64); 1632 psImageInit (wUt, 0.0); 1633 1634 for (int i = 0; i < wUt->numCols; i++) { 1635 for (int j = 0; j < wUt->numRows; j++) { 1636 if (!isfinite(w->data.F64[j])) continue; 1637 if (w->data.F64[j] == 0.0) continue; 1638 wUt->data.F64[j][i] = U->data.F64[i][j] / w->data.F64[j]; 1639 } 1640 } 1641 return wUt; 1642 } 1643 1644 // XXX this is just standard matrix multiplication: use psMatrixMultiply? 1645 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt) { 1646 1647 psAssert (V->numCols == wUt->numRows, "matrix dimensions do not match"); 1648 1649 psImage *Ainv = psImageAlloc (wUt->numCols, V->numRows, PS_TYPE_F64); 1650 1651 for (int i = 0; i < Ainv->numCols; i++) { 1652 for (int j = 0; j < Ainv->numRows; j++) { 1653 double sum = 0.0; 1654 for (int k = 0; k < V->numCols; k++) { 1655 sum += V->data.F64[j][k] * wUt->data.F64[k][i]; 1656 } 1657 Ainv->data.F64[j][i] = sum; 1658 } 1659 } 1660 return Ainv; 1661 } 1662 1663 // we are supplied U, not Ut 1664 psVector *p_pmSubSolve_UtB (psImage *U, psVector *B) { 1665 1666 psAssert (U->numRows == B->n, "U and B dimensions do not match"); 1667 1668 psVector *UtB = psVectorAlloc (U->numCols, PS_TYPE_F64); 1669 1670 for (int i = 0; i < U->numCols; i++) { 1671 double sum = 0.0; 1672 for (int j = 0; j < U->numRows; j++) { 1673 sum += B->data.F64[j] * U->data.F64[j][i]; 1674 } 1675 UtB->data.F64[i] = sum; 1676 } 1677 return UtB; 1678 } 1679 1680 // w is diagonal 1681 psVector *p_pmSubSolve_wUtB (psVector *w, psVector *UtB) { 1682 1683 psAssert (w->n == UtB->n, "w and UtB dimensions do not match"); 1684 1685 // wUt has dimensions transposed relative to Ut. 1686 psVector *wUtB = psVectorAlloc (w->n, PS_TYPE_F64); 1687 psVectorInit (wUtB, 0.0); 1688 1689 for (int i = 0; i < w->n; i++) { 1690 if (!isfinite(w->data.F64[i])) continue; 1691 if (w->data.F64[i] == 0.0) continue; 1692 wUtB->data.F64[i] = UtB->data.F64[i] / w->data.F64[i]; 1693 } 1694 return wUtB; 1695 } 1696 1697 // this is basically matrix * vector 1698 psVector *p_pmSubSolve_VwUtB (psImage *V, psVector *wUtB) { 1699 1700 psAssert (V->numCols == wUtB->n, "V and wUtB dimensions do not match"); 1701 1702 psVector *VwUtB = psVectorAlloc (V->numRows, PS_TYPE_F64); 1703 1704 for (int j = 0; j < V->numRows; j++) { 1705 double sum = 0.0; 1706 for (int i = 0; i < V->numCols; i++) { 1707 sum += V->data.F64[j][i] * wUtB->data.F64[i]; 1708 } 1709 VwUtB->data.F64[j] = sum; 1710 } 1711 return VwUtB; 1712 } 1713 1714 // this is basically matrix * vector 1715 psVector *p_pmSubSolve_Ax (psImage *A, psVector *x) { 1716 1717 psAssert (A->numCols == x->n, "A and x dimensions do not match"); 1718 1719 psVector *B = psVectorAlloc (A->numRows, PS_TYPE_F64); 1720 1721 for (int j = 0; j < A->numRows; j++) { 1722 double sum = 0.0; 1723 for (int i = 0; i < A->numCols; i++) { 1724 sum += A->data.F64[j][i] * x->data.F64[i]; 1725 } 1726 B->data.F64[j] = sum; 1727 } 1728 return B; 1729 } 1730 1731 // this is basically Vector * vector 1732 double p_pmSubSolve_VdV (psVector *x, psVector *y) { 1733 1734 psAssert (x->n == y->n, "x and y dimensions do not match"); 1735 1736 double sum = 0.0; 1737 for (int i = 0; i < x->n; i++) { 1738 sum += x->data.F64[i] * y->data.F64[i]; 1739 } 1740 return sum; 1741 } 1742 1743 double p_pmSubSolve_y2 (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) { 1744 1745 int footprint = stamps->footprint; // Half-size of stamps 1746 1747 double sum = 0.0; 1748 for (int i = 0; i < stamps->num; i++) { 1749 1750 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 1751 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 1752 1753 psKernel *weight = NULL; 1754 psKernel *window = NULL; 1755 psKernel *input = NULL; 1756 1757 #ifdef USE_WEIGHT 1758 weight = stamp->weight; 1759 #endif 1760 #ifdef USE_WINDOW 1761 window = stamps->window; 1762 #endif 1763 1764 switch (kernels->mode) { 1765 // MODE_1 : convolve image 1 to match image 2 (and vice versa) 1766 case PM_SUBTRACTION_MODE_1: 1767 input = stamp->image2; 1768 break; 1769 case PM_SUBTRACTION_MODE_2: 1770 input = stamp->image1; 1771 break; 1772 default: 1773 psAbort ("programming error"); 1774 } 1775 1776 for (int y = - footprint; y <= footprint; y++) { 1777 for (int x = - footprint; x <= footprint; x++) { 1778 double in = input->kernel[y][x]; 1779 double value = in*in; 1780 if (weight) { 1781 float wtVal = weight->kernel[y][x]; 1782 value *= wtVal; 1783 } 1784 if (window) { 1785 float winVal = window->kernel[y][x]; 1786 value *= winVal; 1787 } 1788 sum += value; 1789 } 1790 } 1791 } 1792 return sum; 1793 } 1794 1795 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) { 1796 1797 int footprint = stamps->footprint; // Half-size of stamps 1798 int numKernels = kernels->num; // Number of kernels 1799 1800 double sum = 0.0; 1801 1802 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1803 psImageInit(residual->image, 0.0); 1804 1805 psImage *polyValues = NULL; // Polynomial values 1806 1807 for (int i = 0; i < stamps->num; i++) { 1808 1809 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 1810 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 1811 1812 psKernel *weight = NULL; 1813 psKernel *window = NULL; 1814 psKernel *target = NULL; 1815 psKernel *source = NULL; 1816 1817 psArray *convolutions = NULL; 1818 1819 #ifdef USE_WEIGHT 1820 weight = stamp->weight; 1821 #endif 1822 #ifdef USE_WINDOW 1823 window = stamps->window; 1824 #endif 1825 1826 switch (kernels->mode) { 1827 // MODE_1 : convolve image 1 to match image 2 (and vice versa) 1828 case PM_SUBTRACTION_MODE_1: 1829 target = stamp->image2; 1830 source = stamp->image1; 1831 convolutions = stamp->convolutions1; 1832 break; 1833 case PM_SUBTRACTION_MODE_2: 1834 target = stamp->image1; 1835 source = stamp->image2; 1836 convolutions = stamp->convolutions2; 1837 break; 1838 default: 1839 psAbort ("programming error"); 1840 } 1841 1842 // Calculate coefficients of the kernel basis functions 1843 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm); 1844 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation 1845 double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background 1846 1847 psImageInit(residual->image, 0.0); 1848 for (int j = 0; j < numKernels; j++) { 1849 psKernel *convolution = convolutions->data[j]; // Convolution 1850 double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 1851 for (int y = - footprint; y <= footprint; y++) { 1852 for (int x = - footprint; x <= footprint; x++) { 1853 residual->kernel[y][x] -= convolution->kernel[y][x] * coefficient; 1854 } 1855 } 1856 } 1857 1858 for (int y = - footprint; y <= footprint; y++) { 1859 for (int x = - footprint; x <= footprint; x++) { 1860 double resid = target->kernel[y][x] - background - source->kernel[y][x] * norm + residual->kernel[y][x]; 1861 double value = PS_SQR(resid); 1862 if (weight) { 1863 float wtVal = weight->kernel[y][x]; 1864 value *= wtVal; 1865 } 1866 if (window) { 1867 float winVal = window->kernel[y][x]; 1868 value *= winVal; 1869 } 1870 sum += value; 1871 } 1872 } 1873 } 1874 psFree (polyValues); 1875 psFree (residual); 1876 1877 return sum; 1878 } 1879 1880 // I get confused by the index values between the image vs matrix usage: In terms 1881 // of the elements of an image A(x,y) = A->data.F64[y][x] = A_x,y, a matrix 1882 // multiplication is: A_k,j * B_i,k = C_i,j 1883 1884 1885 bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header) { 1886 1887 psFits *fits = psFitsOpen(filename, "w"); 1888 psFitsWriteImage(fits, header, image, 0, NULL); 1889 psFitsClose(fits); 1890 1891 return true; 1892 } 1893 1894 bool psVectorWriteFile (char *filename, const psVector *vector) { 1895 1896 FILE *f = fopen (filename, "w"); 1897 int fd = fileno(f); 1898 p_psVectorPrint (fd, vector, "unnamed"); 1899 fclose (f); 1900 1901 return true; 1902 } 1903 -
branches/eam_branches/20091201/psModules/src/imcombine/pmSubtractionStamps.c
r26342 r26373 646 646 psVector *flux = psVectorAllocEmpty(2*stamps->num, PS_TYPE_F32); 647 647 648 double maxValue = 0.0; 649 648 650 // generate the window pixels 649 651 for (int y = -size; y <= size; y++) { … … 666 668 } 667 669 stamps->window->kernel[y][x] = stats->robustMedian; 670 if (maxValue < stats->robustMedian) { 671 maxValue = stats->robustMedian; 672 } 673 } 674 } 675 676 // re-normalize so chisquare values are sensible 677 for (int y = -size; y <= size; y++) { 678 for (int x = -size; x <= size; x++) { 679 stamps->window->kernel[y][x] /= maxValue; 668 680 } 669 681 } -
branches/eam_branches/20091201/psModules/src/imcombine/pmSubtractionVisual.c
r26341 r26373 308 308 // if (!pmVisualIsVisual()) return true; 309 309 310 double sum; 311 310 312 int NXoff = index % NX; 311 313 int NYoff = index / NX; … … 315 317 316 318 // insert the (target) kernel into the (target) image: 319 sum = 0.0; 317 320 for (int y = -footprint; y <= footprint; y++) { 318 321 for (int x = -footprint; x <= footprint; x++) { 319 322 targetImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x]; 320 } 321 } 323 sum += targetImage->data.F32[y + NYpix][x + NXpix]; 324 } 325 } 326 targetImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 322 327 323 328 // insert the (source) kernel into the (source) image: 329 sum = 0.0; 324 330 for (int y = -footprint; y <= footprint; y++) { 325 331 for (int x = -footprint; x <= footprint; x++) { 326 332 sourceImage->data.F32[y + NYpix][x + NXpix] = source->kernel[y][x]; 327 } 328 } 329 333 sum += sourceImage->data.F32[y + NYpix][x + NXpix]; 334 } 335 } 336 sourceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 337 330 338 // insert the (convolution) kernel into the (convolution) image: 339 sum = 0.0; 331 340 for (int y = -footprint; y <= footprint; y++) { 332 341 for (int x = -footprint; x <= footprint; x++) { 333 342 convolutionImage->data.F32[y + NYpix][x + NXpix] = -convolution->kernel[y][x]; 334 } 335 } 343 sum += convolutionImage->data.F32[y + NYpix][x + NXpix]; 344 } 345 } 346 convolutionImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 336 347 337 348 // insert the (difference) kernel into the (difference) image: 349 sum = 0.0; 338 350 for (int y = -footprint; y <= footprint; y++) { 339 351 for (int x = -footprint; x <= footprint; x++) { 340 352 differenceImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm; 341 } 342 } 353 sum += differenceImage->data.F32[y + NYpix][x + NXpix]; 354 } 355 } 356 differenceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 343 357 344 358 // insert the (residual) kernel into the (residual) image: 359 sum = 0.0; 345 360 for (int y = -footprint; y <= footprint; y++) { 346 361 for (int x = -footprint; x <= footprint; x++) { 347 362 residualImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm + convolution->kernel[y][x]; 348 } 349 } 363 sum += residualImage->data.F32[y + NYpix][x + NXpix]; 364 } 365 } 366 residualImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 350 367 351 368 // insert the (fresidual) kernel into the (fresidual) image: 352 369 for (int y = -footprint; y <= footprint; y++) { 353 370 for (int x = -footprint; x <= footprint; x++) { 354 fresidualImage->data.F32[y + NYpix][x + NXpix] = PS_SQR(residualImage->data.F32[y + NYpix][x + NXpix]) / (target->kernel[y][x] + 25.0);371 fresidualImage->data.F32[y + NYpix][x + NXpix] = residualImage->data.F32[y + NYpix][x + NXpix] / sqrt(PS_MAX(target->kernel[y][x], 100.0)); 355 372 } 356 373 }
Note:
See TracChangeset
for help on using the changeset viewer.
