Changeset 6183
- Timestamp:
- Jan 22, 2006, 11:12:20 AM (20 years ago)
- Location:
- branches/eam_rel9_p0/psModules/src/objects
- Files:
-
- 2 edited
-
pmObjects.c (modified) (6 diffs)
-
pmObjects.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_rel9_p0/psModules/src/objects/pmObjects.c
r6182 r6183 6 6 * @author EAM, IfA: significant modifications. 7 7 * 8 * @version $Revision: 1.5.4. 3$ $Name: not supported by cvs2svn $9 * @date $Date: 2006-01-22 2 0:20:47$8 * @version $Revision: 1.5.4.4 $ $Name: not supported by cvs2svn $ 9 * @date $Date: 2006-01-22 21:12:19 $ 10 10 * 11 11 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 884 884 // XXX EAM : should this limit be user-defined? 885 885 if (PS_SQR(pDiff) < wDiff) { 886 887 Var += wDiff; 888 Sum += pDiff; 889 890 psF32 xWght = xDiff * pDiff; 891 psF32 yWght = yDiff * pDiff; 892 893 X1 += xWght; 894 Y1 += yWght; 895 XY += xDiff * yWght; 896 897 X2 += xDiff * xWght; 898 Y2 += yDiff * yWght; 899 900 peakPixel = PS_MAX (vPix[row][col], peakPixel); 901 numPixels++; 902 } 903 } 904 905 // if we have less than (1/4) of the possible pixels, force a retry 906 // XXX EAM - the limit is a bit arbitrary. make it user defined? 907 if ((numPixels < 0.75*R2) || (Sum <= 0)) { 908 psTrace (".psModules.pmSourceMoments", 3, "no valid pixels for source\n"); 909 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 910 return (false); 911 } 912 913 psTrace (".psModules.pmSourceMoments", 5, 914 "sky: %f Sum: %f X1: %f Y1: %f X2: %f Y2: %f XY: %f Npix: %d\n", 915 sky, Sum, X1, Y1, X2, Y2, XY, numPixels); 916 917 // 918 // first moment X = X1/Sum + xc 919 // second moment X = sqrt (X2/Sum - (X1/Sum)^2) 920 // Sxy = XY / Sum 921 // 922 x = X1/Sum; 923 y = Y1/Sum; 924 if ((fabs(x) > radius) || (fabs(y) > radius)) { 925 psTrace (".psModules.pmSourceMoments", 3, 926 "large centroid swing; invalid peak %d, %d\n", 927 source->peak->x, source->peak->y); 928 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 929 return (false); 930 } 931 932 source->moments->x = x + xPeak; 933 source->moments->y = y + yPeak; 934 935 // XXX EAM : Sxy needs to have x*y subtracted 936 source->moments->Sxy = XY/Sum - x*y; 937 source->moments->Sum = Sum; 938 source->moments->SN = Sum / sqrt(Var); 939 source->moments->Peak = peakPixel; 940 source->moments->nPixels = numPixels; 941 942 // XXX EAM : these values can be negative, so we need to limit the range 943 source->moments->Sx = sqrt(PS_MAX(X2/Sum - PS_SQR(x), 0)); 944 source->moments->Sy = sqrt(PS_MAX(Y2/Sum - PS_SQR(y), 0)); 945 946 psTrace (".psModules.pmSourceMoments", 4, 947 "sky: %f Sum: %f x: %f y: %f Sx: %f Sy: %f Sxy: %f\n", 948 sky, Sum, source->moments->x, source->moments->y, 949 source->moments->Sx, source->moments->Sy, source->moments->Sxy); 950 951 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 952 return(true); 953 } 954 955 // XXX EAM : I used 956 int pmComparePeakAscend (const void **a, const void **b) { 957 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 958 pmPeak *A = *(pmPeak **)a; 959 pmPeak *B = *(pmPeak **)b; 960 961 psF32 diff; 962 963 diff = A->counts - B->counts; 964 if (diff < FLT_EPSILON) { 965 psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__); 966 return (-1); 967 } else if (diff > FLT_EPSILON) { 968 psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__); 969 return (+1); 970 } 971 psTrace(__func__, 3, "---- %s(0) end ----\n", __func__); 972 return (0); 973 } 974 975 int pmComparePeakDescend (const void **a, const void **b) { 976 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 977 pmPeak *A = *(pmPeak **)a; 978 pmPeak *B = *(pmPeak **)b; 979 980 psF32 diff; 981 982 diff = A->counts - B->counts; 983 if (diff < FLT_EPSILON) { 984 psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__); 985 return (+1); 986 } else if (diff > FLT_EPSILON) { 987 psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__); 988 return (-1); 989 } 990 psTrace(__func__, 3, "---- %s(0) end ----\n", __func__); 991 return (0); 992 } 993 994 /****************************************************************************** 886 continue; 887 } 888 889 Var += wDiff; 890 Sum += pDiff; 891 892 psF32 xWght = xDiff * pDiff; 893 psF32 yWght = yDiff * pDiff; 894 895 X1 += xWght; 896 Y1 += yWght; 897 XY += xDiff * yWght; 898 899 X2 += xDiff * xWght; 900 Y2 += yDiff * yWght; 901 902 peakPixel = PS_MAX (vPix[row][col], peakPixel); 903 numPixels++; 904 } 905 } 906 907 // if we have less than (1/4) of the possible pixels, force a retry 908 // XXX EAM - the limit is a bit arbitrary. make it user defined? 909 if ((numPixels < 0.75*R2) || (Sum <= 0)) { 910 psTrace (".psModules.pmSourceMoments", 3, "no valid pixels for source\n"); 911 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 912 return (false); 913 } 914 915 psTrace (".psModules.pmSourceMoments", 5, 916 "sky: %f Sum: %f X1: %f Y1: %f X2: %f Y2: %f XY: %f Npix: %d\n", 917 sky, Sum, X1, Y1, X2, Y2, XY, numPixels); 918 919 // 920 // first moment X = X1/Sum + xc 921 // second moment X = sqrt (X2/Sum - (X1/Sum)^2) 922 // Sxy = XY / Sum 923 // 924 x = X1/Sum; 925 y = Y1/Sum; 926 if ((fabs(x) > radius) || (fabs(y) > radius)) { 927 psTrace (".psModules.pmSourceMoments", 3, 928 "large centroid swing; invalid peak %d, %d\n", 929 source->peak->x, source->peak->y); 930 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 931 return (false); 932 } 933 934 source->moments->x = x + xPeak; 935 source->moments->y = y + yPeak; 936 937 // XXX EAM : Sxy needs to have x*y subtracted 938 source->moments->Sxy = XY/Sum - x*y; 939 source->moments->Sum = Sum; 940 source->moments->SN = Sum / sqrt(Var); 941 source->moments->Peak = peakPixel; 942 source->moments->nPixels = numPixels; 943 944 // XXX EAM : these values can be negative, so we need to limit the range 945 source->moments->Sx = sqrt(PS_MAX(X2/Sum - PS_SQR(x), 0)); 946 source->moments->Sy = sqrt(PS_MAX(Y2/Sum - PS_SQR(y), 0)); 947 948 psTrace (".psModules.pmSourceMoments", 4, 949 "sky: %f Sum: %f x: %f y: %f Sx: %f Sy: %f Sxy: %f\n", 950 sky, Sum, source->moments->x, source->moments->y, 951 source->moments->Sx, source->moments->Sy, source->moments->Sxy); 952 953 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 954 return(true); 955 } 956 957 // XXX EAM : I used 958 int pmComparePeakAscend (const void **a, const void **b) 959 { 960 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 961 pmPeak *A = *(pmPeak **)a; 962 pmPeak *B = *(pmPeak **)b; 963 964 psF32 diff; 965 966 diff = A->counts - B->counts; 967 if (diff < FLT_EPSILON) { 968 psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__); 969 return (-1); 970 } else if (diff > FLT_EPSILON) { 971 psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__); 972 return (+1); 973 } 974 psTrace(__func__, 3, "---- %s(0) end ----\n", __func__); 975 return (0); 976 } 977 978 int pmComparePeakDescend (const void **a, const void **b) 979 { 980 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 981 pmPeak *A = *(pmPeak **)a; 982 pmPeak *B = *(pmPeak **)b; 983 984 psF32 diff; 985 986 diff = A->counts - B->counts; 987 if (diff < FLT_EPSILON) { 988 psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__); 989 return (+1); 990 } else if (diff > FLT_EPSILON) { 991 psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__); 992 return (-1); 993 } 994 psTrace(__func__, 3, "---- %s(0) end ----\n", __func__); 995 return (0); 996 } 997 998 /****************************************************************************** 995 999 pmSourcePSFClump(source, metadata): Find the likely PSF clump in the 996 1000 sigma-x, sigma-y plane. return 0,0 clump in case of error. 997 *****************************************************************************/ 998 999 // XXX EAM include a S/N cutoff in selecting the sources? 1000 pmPSFClump pmSourcePSFClump(psArray *sources, psMetadata *metadata) { 1001 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1002 1003 # define NPIX 10 1004 # define SCALE 0.1 1005 1006 psArray *peaks = NULL; 1007 pmPSFClump emptyClump = {0.0, 0.0, 0.0, 0.0}; 1008 pmPSFClump psfClump = emptyClump; 1009 1010 PS_ASSERT_PTR_NON_NULL(sources, emptyClump); 1011 PS_ASSERT_PTR_NON_NULL(metadata, emptyClump); 1012 1013 // find the sigmaX, sigmaY clump 1001 *****************************************************************************/ 1002 1003 // XXX EAM include a S/N cutoff in selecting the sources? 1004 pmPSFClump pmSourcePSFClump(psArray *sources, psMetadata *metadata) 1005 { 1006 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1007 1008 # define NPIX 10 1009 # define SCALE 0.1 1010 1011 psArray *peaks = NULL; 1012 pmPSFClump emptyClump = {0.0, 0.0, 0.0, 0.0}; 1013 pmPSFClump psfClump = emptyClump; 1014 1015 PS_ASSERT_PTR_NON_NULL(sources, emptyClump); 1016 PS_ASSERT_PTR_NON_NULL(metadata, emptyClump); 1017 1018 // find the sigmaX, sigmaY clump 1019 { 1020 psStats *stats = NULL; 1021 psImage *splane = NULL; 1022 int binX, binY; 1023 bool status; 1024 1025 psF32 SX_MAX = psMetadataLookupF32 (&status, metadata, "MOMENTS_SX_MAX"); 1026 if (!status) 1027 SX_MAX = 10.0; 1028 psF32 SY_MAX = psMetadataLookupF32 (&status, metadata, "MOMENTS_SY_MAX"); 1029 if (!status) 1030 SY_MAX = 10.0; 1031 1032 // construct a sigma-plane image 1033 // psImageAlloc does zero the data 1034 splane = psImageAlloc (SX_MAX/SCALE, SY_MAX/SCALE, PS_TYPE_F32); 1035 for (int i = 0; i < splane->numRows; i++) 1014 1036 { 1015 psStats *stats = NULL; 1016 psImage *splane = NULL; 1017 int binX, binY; 1018 bool status; 1019 1020 psF32 SX_MAX = psMetadataLookupF32 (&status, metadata, "MOMENTS_SX_MAX"); 1021 if (!status) 1022 SX_MAX = 10.0; 1023 psF32 SY_MAX = psMetadataLookupF32 (&status, metadata, "MOMENTS_SY_MAX"); 1024 if (!status) 1025 SY_MAX = 10.0; 1026 1027 // construct a sigma-plane image 1028 // psImageAlloc does zero the data 1029 splane = psImageAlloc (SX_MAX/SCALE, SY_MAX/SCALE, PS_TYPE_F32); 1030 for (int i = 0; i < splane->numRows; i++) 1031 { 1032 memset (splane->data.F32[i], 0, splane->numCols*sizeof(PS_TYPE_F32)); 1033 } 1034 1035 // place the sources in the sigma-plane image (ignore 0,0 values?) 1036 for (psS32 i = 0 ; i < sources->n ; i++) 1037 { 1038 pmSource *tmpSrc = (pmSource *) sources->data[i]; 1039 if (tmpSrc == NULL) { 1040 continue; 1041 } 1042 if (tmpSrc->moments == NULL) { 1043 continue; 1044 } 1045 1046 // Sx,Sy are limited at 0. a peak at 0,0 is artificial 1047 if ((fabs(tmpSrc->moments->Sx) < FLT_EPSILON) && (fabs(tmpSrc->moments->Sy) < FLT_EPSILON)) { 1048 continue; 1049 } 1050 1051 // for the moment, force splane dimensions to be 10x10 image pix 1052 binX = tmpSrc->moments->Sx/SCALE; 1053 if (binX < 0) 1054 continue; 1055 if (binX >= splane->numCols) 1056 continue; 1057 1058 binY = tmpSrc->moments->Sy/SCALE; 1059 if (binY < 0) 1060 continue; 1061 if (binY >= splane->numRows) 1062 continue; 1063 1064 splane->data.F32[binY][binX] += 1.0; 1065 } 1066 1067 // find the peak in this image 1068 stats = psStatsAlloc (PS_STAT_MAX); 1069 stats = psImageStats (stats, splane, NULL, 0); 1070 peaks = pmFindImagePeaks (splane, stats[0].max / 2); 1071 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump threshold is %f\n", stats[0].max/2); 1072 1073 psFree (splane); 1074 psFree (stats); 1075 1076 } 1077 // XXX EAM : possible errors: 1078 // 1) no peak in splane 1079 // 2) no significant peak in splane 1080 1081 // measure statistics on Sx, Sy if Sx, Sy within range of clump 1037 memset (splane->data.F32[i], 0, splane->numCols*sizeof(PS_TYPE_F32)); 1038 } 1039 1040 // place the sources in the sigma-plane image (ignore 0,0 values?) 1041 for (psS32 i = 0 ; i < sources->n ; i++) 1082 1042 { 1083 pmPeak *clump; 1084 psF32 minSx, maxSx; 1085 psF32 minSy, maxSy; 1086 psVector *tmpSx = NULL; 1087 psVector *tmpSy = NULL; 1088 psStats *stats = NULL; 1089 1090 // XXX EAM : this lets us takes the single highest peak 1091 psArraySort (peaks, pmComparePeakDescend); 1092 clump = peaks->data[0]; 1093 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump is at %d, %d (%f)\n", clump->x, clump->y, clump->counts); 1094 1095 // define section window for clump 1096 minSx = clump->x * SCALE - 0.2; 1097 maxSx = clump->x * SCALE + 0.2; 1098 minSy = clump->y * SCALE - 0.2; 1099 maxSy = clump->y * SCALE + 0.2; 1100 1101 tmpSx = psVectorAlloc (sources->n, PS_TYPE_F32); 1102 tmpSy = psVectorAlloc (sources->n, PS_TYPE_F32); 1103 tmpSx->n = 0; 1104 tmpSy->n = 0; 1105 1106 // XXX clip sources based on flux? 1107 // create vectors with Sx, Sy values in window 1108 for (psS32 i = 0 ; i < sources->n ; i++) 1109 { 1110 pmSource *tmpSrc = (pmSource *) sources->data[i]; 1111 1112 if (tmpSrc->moments->Sx < minSx) 1113 continue; 1114 if (tmpSrc->moments->Sx > maxSx) 1115 continue; 1116 if (tmpSrc->moments->Sy < minSy) 1117 continue; 1118 if (tmpSrc->moments->Sy > maxSy) 1119 continue; 1120 tmpSx->data.F32[tmpSx->n] = tmpSrc->moments->Sx; 1121 tmpSy->data.F32[tmpSy->n] = tmpSrc->moments->Sy; 1122 tmpSx->n++; 1123 tmpSy->n++; 1124 if (tmpSx->n == tmpSx->nalloc) { 1125 psVectorRealloc (tmpSx, tmpSx->nalloc + 100); 1126 psVectorRealloc (tmpSy, tmpSy->nalloc + 100); 1127 } 1128 } 1129 1130 // measures stats of Sx, Sy 1131 stats = psStatsAlloc (PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV); 1132 1133 stats = psVectorStats (stats, tmpSx, NULL, NULL, 0); 1134 psfClump.X = stats->clippedMean; 1135 psfClump.dX = stats->clippedStdev; 1136 1137 stats = psVectorStats (stats, tmpSy, NULL, NULL, 0); 1138 psfClump.Y = stats->clippedMean; 1139 psfClump.dY = stats->clippedStdev; 1140 1141 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump X, Y: %f, %f\n", psfClump.X, psfClump.Y); 1142 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump DX, DY: %f, %f\n", psfClump.dX, psfClump.dY); 1143 // these values should be pushed on the metadata somewhere 1144 1145 psFree (stats); 1146 psFree (peaks); 1147 psFree (tmpSx); 1148 psFree (tmpSy); 1149 } 1150 1151 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1152 return (psfClump); 1153 } 1154 1155 /****************************************************************************** 1043 pmSource *tmpSrc = (pmSource *) sources->data[i]; 1044 if (tmpSrc == NULL) { 1045 continue; 1046 } 1047 if (tmpSrc->moments == NULL) { 1048 continue; 1049 } 1050 1051 // Sx,Sy are limited at 0. a peak at 0,0 is artificial 1052 if ((fabs(tmpSrc->moments->Sx) < FLT_EPSILON) && (fabs(tmpSrc->moments->Sy) < FLT_EPSILON)) { 1053 continue; 1054 } 1055 1056 // for the moment, force splane dimensions to be 10x10 image pix 1057 binX = tmpSrc->moments->Sx/SCALE; 1058 if (binX < 0) 1059 continue; 1060 if (binX >= splane->numCols) 1061 continue; 1062 1063 binY = tmpSrc->moments->Sy/SCALE; 1064 if (binY < 0) 1065 continue; 1066 if (binY >= splane->numRows) 1067 continue; 1068 1069 splane->data.F32[binY][binX] += 1.0; 1070 } 1071 1072 // find the peak in this image 1073 stats = psStatsAlloc (PS_STAT_MAX); 1074 stats = psImageStats (stats, splane, NULL, 0); 1075 peaks = pmFindImagePeaks (splane, stats[0].max / 2); 1076 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump threshold is %f\n", stats[0].max/2); 1077 1078 psFree (splane); 1079 psFree (stats); 1080 1081 } 1082 // XXX EAM : possible errors: 1083 // 1) no peak in splane 1084 // 2) no significant peak in splane 1085 1086 // measure statistics on Sx, Sy if Sx, Sy within range of clump 1087 { 1088 pmPeak *clump; 1089 psF32 minSx, maxSx; 1090 psF32 minSy, maxSy; 1091 psVector *tmpSx = NULL; 1092 psVector *tmpSy = NULL; 1093 psStats *stats = NULL; 1094 1095 // XXX EAM : this lets us takes the single highest peak 1096 psArraySort (peaks, pmComparePeakDescend); 1097 clump = peaks->data[0]; 1098 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump is at %d, %d (%f)\n", clump->x, clump->y, clump->counts); 1099 1100 // define section window for clump 1101 minSx = clump->x * SCALE - 0.2; 1102 maxSx = clump->x * SCALE + 0.2; 1103 minSy = clump->y * SCALE - 0.2; 1104 maxSy = clump->y * SCALE + 0.2; 1105 1106 tmpSx = psVectorAlloc (sources->n, PS_TYPE_F32); 1107 tmpSy = psVectorAlloc (sources->n, PS_TYPE_F32); 1108 tmpSx->n = 0; 1109 tmpSy->n = 0; 1110 1111 // XXX clip sources based on flux? 1112 // create vectors with Sx, Sy values in window 1113 for (psS32 i = 0 ; i < sources->n ; i++) 1114 { 1115 pmSource *tmpSrc = (pmSource *) sources->data[i]; 1116 1117 if (tmpSrc->moments->Sx < minSx) 1118 continue; 1119 if (tmpSrc->moments->Sx > maxSx) 1120 continue; 1121 if (tmpSrc->moments->Sy < minSy) 1122 continue; 1123 if (tmpSrc->moments->Sy > maxSy) 1124 continue; 1125 tmpSx->data.F32[tmpSx->n] = tmpSrc->moments->Sx; 1126 tmpSy->data.F32[tmpSy->n] = tmpSrc->moments->Sy; 1127 tmpSx->n++; 1128 tmpSy->n++; 1129 if (tmpSx->n == tmpSx->nalloc) { 1130 psVectorRealloc (tmpSx, tmpSx->nalloc + 100); 1131 psVectorRealloc (tmpSy, tmpSy->nalloc + 100); 1132 } 1133 } 1134 1135 // measures stats of Sx, Sy 1136 stats = psStatsAlloc (PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV); 1137 1138 stats = psVectorStats (stats, tmpSx, NULL, NULL, 0); 1139 psfClump.X = stats->clippedMean; 1140 psfClump.dX = stats->clippedStdev; 1141 1142 stats = psVectorStats (stats, tmpSy, NULL, NULL, 0); 1143 psfClump.Y = stats->clippedMean; 1144 psfClump.dY = stats->clippedStdev; 1145 1146 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump X, Y: %f, %f\n", psfClump.X, psfClump.Y); 1147 psTrace (".pmObjects.pmSourceRoughClass", 2, "clump DX, DY: %f, %f\n", psfClump.dX, psfClump.dY); 1148 // these values should be pushed on the metadata somewhere 1149 1150 psFree (stats); 1151 psFree (peaks); 1152 psFree (tmpSx); 1153 psFree (tmpSy); 1154 } 1155 1156 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1157 return (psfClump); 1158 } 1159 1160 /****************************************************************************** 1156 1161 pmSourceRoughClass(source, metadata): make a guess at the source 1157 1162 classification. … … 1162 1167 1163 1168 EAM: I moved S/N calculation to pmSourceMoments, using weight image 1164 *****************************************************************************/ 1165 1166 bool pmSourceRoughClass(psArray *sources, psMetadata *metadata, pmPSFClump clump) { 1167 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1168 1169 psBool rc = true; 1170 1171 int Nsat = 0; 1172 int Next = 0; 1173 int Nstar = 0; 1174 int Npsf = 0; 1175 int Ncr = 0; 1176 int Nsatstar = 0; 1177 // psRegion allArray = psRegionSet (0, 0, 0, 0); 1178 psRegion inner; 1179 1180 // report stats on S/N values for star-like objects 1181 psVector *starsn = psVectorAlloc (sources->n, PS_TYPE_F32); 1182 starsn->n = 0; 1183 1184 // check return status value (do these exist?) 1185 bool status; 1186 psF32 PSF_SN_LIM = psMetadataLookupF32 (&status, metadata, "PSF_SN_LIM"); 1187 1188 // XXX allow clump size to be scaled relative to sigmas? 1189 // make rough IDs based on clumpX,Y,DX,DY 1190 for (psS32 i = 0 ; i < sources->n ; i++) { 1191 1192 pmSource *tmpSrc = (pmSource *) sources->data[i]; 1193 1194 tmpSrc->peak->class = 0; 1195 1196 psF32 sigX = tmpSrc->moments->Sx; 1197 psF32 sigY = tmpSrc->moments->Sy; 1198 1199 // XXX EAM : can we use the value of SATURATE if mask is NULL? 1200 inner = psRegionForSquare (tmpSrc->peak->x - tmpSrc->mask->col0, tmpSrc->peak->y - tmpSrc->mask->row0, 2); 1201 int Nsatpix = psImageCountPixelMask (tmpSrc->mask, inner, PSPHOT_MASK_SATURATED); 1202 1203 // saturated star (size consistent with PSF or larger) 1204 // Nsigma should be user-configured parameter 1205 bool big = (sigX > (clump.X - clump.dX)) && (sigY > (clump.Y - clump.dY)); 1206 big = true; 1207 if ((Nsatpix > 1) && big) { 1208 tmpSrc->type = PM_SOURCE_STAR; 1209 tmpSrc->mode = PM_SOURCE_SATSTAR; 1210 Nsatstar ++; 1211 continue; 1212 } 1213 1214 // saturated object (not a star, eg bleed trails, hot pixels) 1215 if (Nsatpix > 1) { 1216 tmpSrc->type = PM_SOURCE_SATURATED; 1217 tmpSrc->mode = PM_SOURCE_DEFAULT; 1218 Nsat ++; 1219 continue; 1220 } 1221 1222 // likely defect (too small to be stellar) (push out to 3 sigma) 1223 // low S/N objects which are small are probably stellar 1224 // only set candidate defects if 1225 if ((sigX < 0.05) || (sigY < 0.05)) { 1226 tmpSrc->type = PM_SOURCE_DEFECT; 1227 tmpSrc->mode = PM_SOURCE_DEFAULT; 1228 Ncr ++; 1229 continue; 1230 } 1231 1232 // likely unsaturated extended source (too large to be stellar) 1233 if ((sigX > (clump.X + 3*clump.dX)) || (sigY > (clump.Y + 3*clump.dY))) { 1234 tmpSrc->type = PM_SOURCE_EXTENDED; 1235 tmpSrc->mode = PM_SOURCE_DEFAULT; 1236 Next ++; 1237 continue; 1238 } 1239 1240 // the rest are probable stellar objects 1241 starsn->data.F32[starsn->n] = tmpSrc->moments->SN; 1242 starsn->n ++; 1243 Nstar ++; 1244 1245 // PSF star (within 1.5 sigma of clump center, S/N > limit) 1246 psF32 radius = hypot ((sigX-clump.X)/clump.dX, (sigY-clump.Y)/clump.dY); 1247 if ((tmpSrc->moments->SN > PSF_SN_LIM) && (radius < 1.5)) { 1248 tmpSrc->type = PM_SOURCE_STAR; 1249 tmpSrc->mode = PM_SOURCE_PSFSTAR; 1250 Npsf ++; 1251 continue; 1252 } 1253 1254 // random type of star 1169 *****************************************************************************/ 1170 1171 bool pmSourceRoughClass(psArray *sources, psMetadata *metadata, pmPSFClump clump) 1172 { 1173 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1174 1175 psBool rc = true; 1176 1177 int Nsat = 0; 1178 int Next = 0; 1179 int Nstar = 0; 1180 int Npsf = 0; 1181 int Ncr = 0; 1182 int Nsatstar = 0; 1183 // psRegion allArray = psRegionSet (0, 0, 0, 0); 1184 psRegion inner; 1185 1186 // report stats on S/N values for star-like objects 1187 psVector *starsn = psVectorAlloc (sources->n, PS_TYPE_F32); 1188 starsn->n = 0; 1189 1190 // check return status value (do these exist?) 1191 bool status; 1192 psF32 PSF_SN_LIM = psMetadataLookupF32 (&status, metadata, "PSF_SN_LIM"); 1193 1194 // XXX allow clump size to be scaled relative to sigmas? 1195 // make rough IDs based on clumpX,Y,DX,DY 1196 for (psS32 i = 0 ; i < sources->n ; i++) { 1197 1198 pmSource *tmpSrc = (pmSource *) sources->data[i]; 1199 1200 tmpSrc->peak->class = 0; 1201 1202 psF32 sigX = tmpSrc->moments->Sx; 1203 psF32 sigY = tmpSrc->moments->Sy; 1204 1205 // XXX EAM : can we use the value of SATURATE if mask is NULL? 1206 inner = psRegionForSquare (tmpSrc->peak->x - tmpSrc->mask->col0, tmpSrc->peak->y - tmpSrc->mask->row0, 2); 1207 int Nsatpix = psImageCountPixelMask (tmpSrc->mask, inner, PSPHOT_MASK_SATURATED); 1208 1209 // saturated star (size consistent with PSF or larger) 1210 // Nsigma should be user-configured parameter 1211 bool big = (sigX > (clump.X - clump.dX)) && (sigY > (clump.Y - clump.dY)); 1212 big = true; 1213 if ((Nsatpix > 1) && big) { 1255 1214 tmpSrc->type = PM_SOURCE_STAR; 1215 tmpSrc->mode = PM_SOURCE_SATSTAR; 1216 Nsatstar ++; 1217 continue; 1218 } 1219 1220 // saturated object (not a star, eg bleed trails, hot pixels) 1221 if (Nsatpix > 1) { 1222 tmpSrc->type = PM_SOURCE_SATURATED; 1256 1223 tmpSrc->mode = PM_SOURCE_DEFAULT; 1257 } 1258 1259 { 1260 psStats *stats = NULL; 1261 stats = psStatsAlloc (PS_STAT_MIN | PS_STAT_MAX); 1262 stats = psVectorStats (stats, starsn, NULL, NULL, 0); 1263 psLogMsg ("pmObjects", 3, "SN range: %f - %f\n", stats[0].min, stats[0].max); 1264 psFree (stats); 1265 psFree (starsn); 1266 } 1267 1268 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nstar: %3d\n", Nstar); 1269 psTrace (".pmObjects.pmSourceRoughClass", 2, "Npsf: %3d\n", Npsf); 1270 psTrace (".pmObjects.pmSourceRoughClass", 2, "Next: %3d\n", Next); 1271 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsatstar: %3d\n", Nsatstar); 1272 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsat: %3d\n", Nsat); 1273 psTrace (".pmObjects.pmSourceRoughClass", 2, "Ncr: %3d\n", Ncr); 1274 1275 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1276 return(rc); 1277 } 1278 1279 /** pmSourceDefinePixels() 1280 * 1281 * Define psImage subarrays for the source located at coordinates x,y on the 1282 * image set defined by readout. The pixels defined by this operation consist of 1283 * a square window (of full width 2Radius+1) centered on the pixel which contains 1284 * the given coordinate, in the frame of the readout. The window is defined to 1285 * have limits which are valid within the boundary of the readout image, thus if 1286 * the radius would fall outside the image pixels, the subimage is truncated to 1287 * only consist of valid pixels. If readout->mask or readout->weight are not 1288 * NULL, matching subimages are defined for those images as well. This function 1289 * fails if no valid pixels can be defined (x or y less than Radius, for 1290 * example). This function should be used to define a region of interest around a 1291 * source, including both source and sky pixels. 1292 * 1293 * XXX: must code this. 1294 * 1295 */ 1296 bool pmSourceDefinePixels( 1297 pmSource *mySource, ///< Add comment. 1298 pmReadout *readout, ///< Add comment. 1299 psF32 x, ///< Add comment. 1300 psF32 y, ///< Add comment. 1301 psF32 Radius) ///< Add comment. 1224 Nsat ++; 1225 continue; 1226 } 1227 1228 // likely defect (too small to be stellar) (push out to 3 sigma) 1229 // low S/N objects which are small are probably stellar 1230 // only set candidate defects if 1231 if ((sigX < 0.05) || (sigY < 0.05)) { 1232 tmpSrc->type = PM_SOURCE_DEFECT; 1233 tmpSrc->mode = PM_SOURCE_DEFAULT; 1234 Ncr ++; 1235 continue; 1236 } 1237 1238 // likely unsaturated extended source (too large to be stellar) 1239 if ((sigX > (clump.X + 3*clump.dX)) || (sigY > (clump.Y + 3*clump.dY))) { 1240 tmpSrc->type = PM_SOURCE_EXTENDED; 1241 tmpSrc->mode = PM_SOURCE_DEFAULT; 1242 Next ++; 1243 continue; 1244 } 1245 1246 // the rest are probable stellar objects 1247 starsn->data.F32[starsn->n] = tmpSrc->moments->SN; 1248 starsn->n ++; 1249 Nstar ++; 1250 1251 // PSF star (within 1.5 sigma of clump center, S/N > limit) 1252 psF32 radius = hypot ((sigX-clump.X)/clump.dX, (sigY-clump.Y)/clump.dY); 1253 if ((tmpSrc->moments->SN > PSF_SN_LIM) && (radius < 1.5)) { 1254 tmpSrc->type = PM_SOURCE_STAR; 1255 tmpSrc->mode = PM_SOURCE_PSFSTAR; 1256 Npsf ++; 1257 continue; 1258 } 1259 1260 // random type of star 1261 tmpSrc->type = PM_SOURCE_STAR; 1262 tmpSrc->mode = PM_SOURCE_DEFAULT; 1263 } 1264 1302 1265 { 1303 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1304 psLogMsg(__func__, PS_LOG_WARN, "WARNING: pmSourceDefinePixels() has not been implemented. Returning FALSE.\n"); 1305 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1306 return(false); 1307 } 1308 1309 /****************************************************************************** 1266 psStats *stats = NULL; 1267 stats = psStatsAlloc (PS_STAT_MIN | PS_STAT_MAX); 1268 stats = psVectorStats (stats, starsn, NULL, NULL, 0); 1269 psLogMsg ("pmObjects", 3, "SN range: %f - %f\n", stats[0].min, stats[0].max); 1270 psFree (stats); 1271 psFree (starsn); 1272 } 1273 1274 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nstar: %3d\n", Nstar); 1275 psTrace (".pmObjects.pmSourceRoughClass", 2, "Npsf: %3d\n", Npsf); 1276 psTrace (".pmObjects.pmSourceRoughClass", 2, "Next: %3d\n", Next); 1277 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsatstar: %3d\n", Nsatstar); 1278 psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsat: %3d\n", Nsat); 1279 psTrace (".pmObjects.pmSourceRoughClass", 2, "Ncr: %3d\n", Ncr); 1280 1281 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1282 return(rc); 1283 } 1284 1285 /** pmSourceDefinePixels() 1286 * 1287 * Define psImage subarrays for the source located at coordinates x,y on the 1288 * image set defined by readout. The pixels defined by this operation consist of 1289 * a square window (of full width 2Radius+1) centered on the pixel which contains 1290 * the given coordinate, in the frame of the readout. The window is defined to 1291 * have limits which are valid within the boundary of the readout image, thus if 1292 * the radius would fall outside the image pixels, the subimage is truncated to 1293 * only consist of valid pixels. If readout->mask or readout->weight are not 1294 * NULL, matching subimages are defined for those images as well. This function 1295 * fails if no valid pixels can be defined (x or y less than Radius, for 1296 * example). This function should be used to define a region of interest around a 1297 * source, including both source and sky pixels. 1298 * 1299 * XXX: must code this. 1300 * 1301 */ 1302 bool pmSourceDefinePixels( 1303 pmSource *mySource, ///< Add comment. 1304 pmReadout *readout, ///< Add comment. 1305 psF32 x, ///< Add comment. 1306 psF32 y, ///< Add comment. 1307 psF32 Radius) ///< Add comment. 1308 { 1309 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1310 psLogMsg(__func__, PS_LOG_WARN, "WARNING: pmSourceDefinePixels() has not been implemented. Returning FALSE.\n"); 1311 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1312 return(false); 1313 } 1314 1315 /****************************************************************************** 1310 1316 pmSourceSetPixelsCircle(source, image, radius) 1311 1317 1312 1318 XXX: This was replaced by DefinePixels in SDRS. Remove it. 1313 *****************************************************************************/ 1314 bool pmSourceSetPixelsCircle(pmSource *source, 1315 const psImage *image, 1316 psF32 radius) { 1317 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1318 PS_ASSERT_IMAGE_NON_NULL(image, false); 1319 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 1320 PS_ASSERT_PTR_NON_NULL(source, false); 1321 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1322 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1323 PS_FLOAT_COMPARE(0.0, radius, false); 1324 1325 // 1326 // We define variables for code readability. 1327 // 1328 // XXX: Since the peak->xy coords are in image, not subImage coords, 1329 // these variables should be renamed for clarity (imageCenterRow, etc). 1330 // 1331 psS32 radiusS32 = (psS32) radius; 1332 psS32 SubImageCenterRow = source->peak->y; 1333 psS32 SubImageCenterCol = source->peak->x; 1334 // XXX EAM : for the circle to stay on the image 1335 // XXX EAM : EndRow is *exclusive* of pixel region (ie, last pixel + 1) 1336 psS32 SubImageStartRow = PS_MAX (0, SubImageCenterRow - radiusS32); 1337 psS32 SubImageEndRow = PS_MIN (image->numRows, SubImageCenterRow + radiusS32 + 1); 1338 psS32 SubImageStartCol = PS_MAX (0, SubImageCenterCol - radiusS32); 1339 psS32 SubImageEndCol = PS_MIN (image->numCols, SubImageCenterCol + radiusS32 + 1); 1340 1341 // XXX: Must recycle image. 1342 // XXX EAM: this message reflects a programming error we know about. 1343 // i am setting it to a trace message which we can take out 1344 if (source->pixels != NULL) { 1345 psTrace (".psModule.pmObjects.pmSourceSetPixelsCircle", 4, 1346 "WARNING: pmSourceSetPixelsCircle(): image->pixels not NULL. Freeing and reallocating.\n"); 1347 psFree(source->pixels); 1348 } 1349 source->pixels = psImageSubset((psImage *) image, psRegionSet(SubImageStartCol, 1350 SubImageStartRow, 1351 SubImageEndCol, 1352 SubImageEndRow)); 1353 1354 // XXX: Must recycle image. 1355 if (source->mask != NULL) { 1356 psFree(source->mask); 1357 } 1358 source->mask = psImageAlloc(source->pixels->numCols, 1359 source->pixels->numRows, 1360 PS_TYPE_U8); // XXX EAM : type was F32 1361 1362 // 1363 // Loop through the subimage mask, initialize mask to 0 or 1. 1364 // XXX EAM: valid pixels should have 0, not 1 1365 for (psS32 row = 0 ; row < source->mask->numRows; row++) { 1366 for (psS32 col = 0 ; col < source->mask->numCols; col++) { 1367 1368 if (checkRadius2((psF32) radiusS32, 1369 (psF32) radiusS32, 1370 radius, 1371 (psF32) col, 1372 (psF32) row)) { 1373 source->mask->data.U8[row][col] = 0; 1374 } else { 1375 source->mask->data.U8[row][col] = 1; 1376 } 1377 } 1378 } 1379 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 1380 return(true); 1381 } 1382 1383 /****************************************************************************** 1319 *****************************************************************************/ 1320 bool pmSourceSetPixelsCircle(pmSource *source, 1321 const psImage *image, 1322 psF32 radius) 1323 { 1324 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1325 PS_ASSERT_IMAGE_NON_NULL(image, false); 1326 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 1327 PS_ASSERT_PTR_NON_NULL(source, false); 1328 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1329 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1330 PS_FLOAT_COMPARE(0.0, radius, false); 1331 1332 // 1333 // We define variables for code readability. 1334 // 1335 // XXX: Since the peak->xy coords are in image, not subImage coords, 1336 // these variables should be renamed for clarity (imageCenterRow, etc). 1337 // 1338 psS32 radiusS32 = (psS32) radius; 1339 psS32 SubImageCenterRow = source->peak->y; 1340 psS32 SubImageCenterCol = source->peak->x; 1341 // XXX EAM : for the circle to stay on the image 1342 // XXX EAM : EndRow is *exclusive* of pixel region (ie, last pixel + 1) 1343 psS32 SubImageStartRow = PS_MAX (0, SubImageCenterRow - radiusS32); 1344 psS32 SubImageEndRow = PS_MIN (image->numRows, SubImageCenterRow + radiusS32 + 1); 1345 psS32 SubImageStartCol = PS_MAX (0, SubImageCenterCol - radiusS32); 1346 psS32 SubImageEndCol = PS_MIN (image->numCols, SubImageCenterCol + radiusS32 + 1); 1347 1348 // XXX: Must recycle image. 1349 // XXX EAM: this message reflects a programming error we know about. 1350 // i am setting it to a trace message which we can take out 1351 if (source->pixels != NULL) { 1352 psTrace (".psModule.pmObjects.pmSourceSetPixelsCircle", 4, 1353 "WARNING: pmSourceSetPixelsCircle(): image->pixels not NULL. Freeing and reallocating.\n"); 1354 psFree(source->pixels); 1355 } 1356 source->pixels = psImageSubset((psImage *) image, psRegionSet(SubImageStartCol, 1357 SubImageStartRow, 1358 SubImageEndCol, 1359 SubImageEndRow)); 1360 1361 // XXX: Must recycle image. 1362 if (source->mask != NULL) { 1363 psFree(source->mask); 1364 } 1365 source->mask = psImageAlloc(source->pixels->numCols, 1366 source->pixels->numRows, 1367 PS_TYPE_U8); // XXX EAM : type was F32 1368 1369 // 1370 // Loop through the subimage mask, initialize mask to 0 or 1. 1371 // XXX EAM: valid pixels should have 0, not 1 1372 for (psS32 row = 0 ; row < source->mask->numRows; row++) { 1373 for (psS32 col = 0 ; col < source->mask->numCols; col++) { 1374 1375 if (checkRadius2((psF32) radiusS32, 1376 (psF32) radiusS32, 1377 radius, 1378 (psF32) col, 1379 (psF32) row)) { 1380 source->mask->data.U8[row][col] = 0; 1381 } else { 1382 source->mask->data.U8[row][col] = 1; 1383 } 1384 } 1385 } 1386 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 1387 return(true); 1388 } 1389 1390 /****************************************************************************** 1384 1391 pmSourceModelGuess(source, model): This function allocates a new 1385 1392 pmModel structure based on the given modelType specified in the argument list. … … 1390 1397 image, not subImage coords. Therefore, the calls to the model evaluation 1391 1398 functions will be in image, not subImage coords. Remember this. 1392 *****************************************************************************/ 1393 pmModel *pmSourceModelGuess(pmSource *source, 1394 pmModelType modelType) { 1395 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1396 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1397 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1398 1399 pmModel *model = pmModelAlloc(modelType); 1400 1401 pmModelGuessFunc modelGuessFunc = pmModelGuessFunc_GetFunction(modelType); 1402 modelGuessFunc(model, source); 1403 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1404 return(model); 1405 } 1406 1407 /****************************************************************************** 1399 *****************************************************************************/ 1400 pmModel *pmSourceModelGuess(pmSource *source, 1401 pmModelType modelType) 1402 { 1403 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1404 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1405 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1406 1407 pmModel *model = pmModelAlloc(modelType); 1408 1409 pmModelGuessFunc modelGuessFunc = pmModelGuessFunc_GetFunction(modelType); 1410 modelGuessFunc(model, source); 1411 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1412 return(model); 1413 } 1414 1415 /****************************************************************************** 1408 1416 evalModel(source, level, row): a private function which evaluates the 1409 1417 source->modelPSF function at the specified coords. The coords are subImage, not … … 1425 1433 XXX: For a while, the first psVectorAlloc() was generating a seg fault during 1426 1434 testing. Try to reproduce that and debug. 1427 *****************************************************************************/ 1428 1429 // XXX EAM : I have made this a public function 1430 // XXX EAM : this now uses a pmModel as the input 1431 // XXX EAM : it was using src->type to find the model, not model->type 1432 psF32 pmModelEval(pmModel *model, psImage *image, psS32 col, psS32 row) { 1433 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1434 PS_ASSERT_PTR_NON_NULL(image, false); 1435 PS_ASSERT_PTR_NON_NULL(model, false); 1436 PS_ASSERT_PTR_NON_NULL(model->params, false); 1437 1438 // Allocate the x coordinate structure and convert row/col to image space. 1439 // 1440 psVector *x = psVectorAlloc(2, PS_TYPE_F32); 1441 x->data.F32[0] = (psF32) (col + image->col0); 1442 x->data.F32[1] = (psF32) (row + image->row0); 1443 psF32 tmpF; 1444 pmModelFunc modelFunc; 1445 1446 modelFunc = pmModelFunc_GetFunction (model->type); 1447 tmpF = modelFunc (NULL, model->params, x); 1448 psFree(x); 1449 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1450 return(tmpF); 1451 } 1452 1453 /****************************************************************************** 1435 *****************************************************************************/ 1436 1437 // XXX EAM : I have made this a public function 1438 // XXX EAM : this now uses a pmModel as the input 1439 // XXX EAM : it was using src->type to find the model, not model->type 1440 psF32 pmModelEval(pmModel *model, psImage *image, psS32 col, psS32 row) 1441 { 1442 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1443 PS_ASSERT_PTR_NON_NULL(image, false); 1444 PS_ASSERT_PTR_NON_NULL(model, false); 1445 PS_ASSERT_PTR_NON_NULL(model->params, false); 1446 1447 // Allocate the x coordinate structure and convert row/col to image space. 1448 // 1449 psVector *x = psVectorAlloc(2, PS_TYPE_F32); 1450 x->data.F32[0] = (psF32) (col + image->col0); 1451 x->data.F32[1] = (psF32) (row + image->row0); 1452 psF32 tmpF; 1453 pmModelFunc modelFunc; 1454 1455 modelFunc = pmModelFunc_GetFunction (model->type); 1456 tmpF = modelFunc (NULL, model->params, x); 1457 psFree(x); 1458 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1459 return(tmpF); 1460 } 1461 1462 /****************************************************************************** 1454 1463 pmSourceContour(src, img, level, mode): For an input subImage, and model, this 1455 1464 routine returns a psArray of coordinates that evaluate to the specified level. … … 1463 1472 XXX EAM : this function is using the model for the contour, but it should 1464 1473 be using only the image counts 1465 *****************************************************************************/ 1466 psArray *pmSourceContour(pmSource *source, 1467 const psImage *image, 1468 psF32 level, 1469 pmContourType mode) { 1470 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1471 PS_ASSERT_PTR_NON_NULL(source, false); 1472 PS_ASSERT_PTR_NON_NULL(image, false); 1473 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1474 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1475 PS_ASSERT_PTR_NON_NULL(source->pixels, false); 1476 PS_ASSERT_PTR_NON_NULL(source->modelEXT, false); 1477 // XXX EAM : what is the purpose of modelPSF/modelEXT? 1478 1479 // 1480 // Allocate data for x/y pairs. 1481 // 1482 psVector *xVec = psVectorAlloc(2 * source->pixels->numRows, PS_TYPE_F32); 1483 psVector *yVec = psVectorAlloc(2 * source->pixels->numRows, PS_TYPE_F32); 1484 1485 // 1486 // Start at the row with peak pixel, then decrement. 1487 // 1488 psS32 col = source->peak->x; 1489 for (psS32 row = source->peak->y; row>= 0 ; row--) { 1490 // XXX: yVec contain no real information. Do we really need it? 1491 yVec->data.F32[row] = (psF32) (source->pixels->row0 + row); 1492 yVec->data.F32[row+yVec->n] = (psF32) (source->pixels->row0 + row); 1493 1494 // Starting at peak pixel, search leftwards for the column intercept. 1495 psF32 leftIntercept = findValue(source, level, row, col, 0); 1496 if (isnan(leftIntercept)) { 1497 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)"); 1498 psFree(xVec); 1499 psFree(yVec); 1500 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1501 return(NULL); 1502 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); 1503 } 1504 xVec->data.F32[row] = ((psF32) source->pixels->col0) + leftIntercept; 1505 1506 // Starting at peak pixel, search rightwards for the column intercept. 1507 1508 psF32 rightIntercept = findValue(source, level, row, col, 1); 1509 if (isnan(rightIntercept)) { 1510 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)"); 1511 psFree(xVec); 1512 psFree(yVec); 1513 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1514 return(NULL); 1515 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); 1516 } 1517 psTrace(__func__, 4, "The intercepts are (%.2f, %.2f)\n", leftIntercept, rightIntercept); 1518 xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept; 1519 1520 // Set starting column for next row 1521 col = (psS32) ((leftIntercept + rightIntercept) / 2.0); 1522 } 1523 // 1524 // Start at the row (+1) with peak pixel, then increment. 1525 // 1526 col = source->peak->x; 1527 for (psS32 row = 1 + source->peak->y; row < source->pixels->numRows ; row++) { 1528 // XXX: yVec contain no real information. Do we really need it? 1529 yVec->data.F32[row] = (psF32) (source->pixels->row0 + row); 1530 yVec->data.F32[row+yVec->n] = (psF32) (source->pixels->row0 + row); 1531 1532 // Starting at peak pixel, search leftwards for the column intercept. 1533 psF32 leftIntercept = findValue(source, level, row, col, 0); 1534 if (isnan(leftIntercept)) { 1535 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)"); 1536 psFree(xVec); 1537 psFree(yVec); 1538 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1539 return(NULL); 1540 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); 1541 } 1542 xVec->data.F32[row] = ((psF32) source->pixels->col0) + leftIntercept; 1543 1544 // Starting at peak pixel, search rightwards for the column intercept. 1545 psF32 rightIntercept = findValue(source, level, row, col, 1); 1546 if (isnan(rightIntercept)) { 1547 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)"); 1548 psFree(xVec); 1549 psFree(yVec); 1550 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1551 return(NULL); 1552 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); 1553 } 1554 xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept; 1555 1556 // Set starting column for next row 1557 col = (psS32) ((leftIntercept + rightIntercept) / 2.0); 1558 } 1559 1560 // 1561 // Allocate an array for result, store coord vectors there. 1562 // 1563 psArray *tmpArray = psArrayAlloc(2); 1564 tmpArray->data[0] = (psPtr *) yVec; 1565 tmpArray->data[1] = (psPtr *) xVec; 1566 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1567 return(tmpArray); 1568 } 1569 1570 // save a static values so they may be set externally 1571 static psF32 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = 15; 1572 static psF32 PM_SOURCE_FIT_MODEL_TOLERANCE = 0.1; 1573 1574 bool pmSourceFitModelInit (float nIter, float tol) { 1575 1576 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = nIter; 1577 PM_SOURCE_FIT_MODEL_TOLERANCE = tol; 1578 } 1579 1580 bool pmSourceFitModel (pmSource *source, 1581 pmModel *model, 1582 const bool PSF) { 1583 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1584 PS_ASSERT_PTR_NON_NULL(source, false); 1585 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1586 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1587 PS_ASSERT_PTR_NON_NULL(source->pixels, false); 1588 PS_ASSERT_PTR_NON_NULL(source->mask, false); 1589 PS_ASSERT_PTR_NON_NULL(source->weight, false); 1590 1591 // XXX EAM : is it necessary for the mask & weight to exist? the 1592 // tests below could be conditions (!NULL) 1593 1594 psBool fitStatus = true; 1595 psBool onPic = true; 1596 psBool rc = true; 1597 1598 psVector *params = model->params; 1599 psVector *dparams = model->dparams; 1600 psVector *paramMask = NULL; 1601 1602 pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type); 1603 1604 int nParams = PSF ? 4 : params->n; 1605 1606 // maximum number of valid pixels 1607 psS32 nPix = source->pixels->numRows * source->pixels->numCols; 1608 1609 // construct the coordinate and value entries 1610 psArray *x = psArrayAlloc(nPix); 1611 psVector *y = psVectorAlloc(nPix, PS_TYPE_F32); 1612 psVector *yErr = psVectorAlloc(nPix, PS_TYPE_F32); 1613 1614 nPix = 0; 1615 for (psS32 i = 0; i < source->pixels->numRows; i++) { 1616 for (psS32 j = 0; j < source->pixels->numCols; j++) { 1617 if (source->mask->data.U8[i][j]) { 1618 continue; 1619 } 1620 psVector *coord = psVectorAlloc(2, PS_TYPE_F32); 1621 1622 // Convert i/j to image space: 1623 coord->data.F32[0] = (psF32) (j + source->pixels->col0); 1624 coord->data.F32[1] = (psF32) (i + source->pixels->row0); 1625 x->data[nPix] = (psPtr *) coord; 1626 y->data.F32[nPix] = source->pixels->data.F32[i][j]; 1627 1628 // psMinimizeLMChi2 takes wt = 1/dY^2 1629 if (source->weight->data.F32[i][j] == 0) { 1630 continue; 1631 } 1632 yErr->data.F32[nPix] = 1.0 / source->weight->data.F32[i][j]; 1633 nPix++; 1634 } 1635 } 1636 if (nPix < nParams + 1) { 1637 psTrace (".pmObjects.pmSourceFitModel", 4, "insufficient valid pixels\n"); 1638 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 1639 model->status = PM_MODEL_BADARGS; 1640 psFree (x); 1641 psFree (y); 1642 psFree (yErr); 1643 return(false); 1644 } 1645 x->n = nPix; 1646 y->n = nPix; 1647 yErr->n = nPix; 1648 1649 psMinimization *myMin = psMinimizationAlloc(PM_SOURCE_FIT_MODEL_NUM_ITERATIONS, 1650 PM_SOURCE_FIT_MODEL_TOLERANCE); 1651 1652 // PSF model only fits first 4 parameters, EXT model fits all 1653 if (PSF) { 1654 paramMask = psVectorAlloc (params->n, PS_TYPE_U8); 1655 for (int i = 0; i < 4; i++) { 1656 paramMask->data.U8[i] = 0; 1657 } 1658 for (int i = 4; i < paramMask->n; i++) { 1659 paramMask->data.U8[i] = 1; 1660 } 1661 } 1662 1663 // Set the parameter range checks 1664 pmModelLimits modelLimits = pmModelLimits_GetFunction (model->type); 1665 psVector *beta_lim = NULL; 1666 psVector *params_min = NULL; 1667 psVector *params_max = NULL; 1668 1669 // XXX EAM : in this implementation, I pass in the limits with the covar matrix. 1670 // in the SDRS, I define a new psMinimization which will take these in 1671 psImage *covar = psImageAlloc (params->n, 3, PS_TYPE_F64); 1672 modelLimits (&beta_lim, ¶ms_min, ¶ms_max); 1673 for (int i = 0; i < params->n; i++) { 1674 covar->data.F64[0][i] = beta_lim->data.F32[i]; 1675 covar->data.F64[1][i] = params_min->data.F32[i]; 1676 covar->data.F64[2][i] = params_max->data.F32[i]; 1677 } 1678 1679 psTrace (".pmObjects.pmSourceFitModel", 5, "fitting function\n"); 1680 fitStatus = psMinimizeLMChi2(myMin, covar, params, paramMask, x, y, yErr, modelFunc); 1474 *****************************************************************************/ 1475 psArray *pmSourceContour(pmSource *source, 1476 const psImage *image, 1477 psF32 level, 1478 pmContourType mode) 1479 { 1480 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1481 PS_ASSERT_PTR_NON_NULL(source, false); 1482 PS_ASSERT_PTR_NON_NULL(image, false); 1483 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1484 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1485 PS_ASSERT_PTR_NON_NULL(source->pixels, false); 1486 PS_ASSERT_PTR_NON_NULL(source->modelEXT, false); 1487 // XXX EAM : what is the purpose of modelPSF/modelEXT? 1488 1489 // 1490 // Allocate data for x/y pairs. 1491 // 1492 psVector *xVec = psVectorAlloc(2 * source->pixels->numRows, PS_TYPE_F32); 1493 psVector *yVec = psVectorAlloc(2 * source->pixels->numRows, PS_TYPE_F32); 1494 1495 // 1496 // Start at the row with peak pixel, then decrement. 1497 // 1498 psS32 col = source->peak->x; 1499 for (psS32 row = source->peak->y; row>= 0 ; row--) { 1500 // XXX: yVec contain no real information. Do we really need it? 1501 yVec->data.F32[row] = (psF32) (source->pixels->row0 + row); 1502 yVec->data.F32[row+yVec->n] = (psF32) (source->pixels->row0 + row); 1503 1504 // Starting at peak pixel, search leftwards for the column intercept. 1505 psF32 leftIntercept = findValue(source, level, row, col, 0); 1506 if (isnan(leftIntercept)) { 1507 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)"); 1508 psFree(xVec); 1509 psFree(yVec); 1510 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1511 return(NULL); 1512 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); 1513 } 1514 xVec->data.F32[row] = ((psF32) source->pixels->col0) + leftIntercept; 1515 1516 // Starting at peak pixel, search rightwards for the column intercept. 1517 1518 psF32 rightIntercept = findValue(source, level, row, col, 1); 1519 if (isnan(rightIntercept)) { 1520 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)"); 1521 psFree(xVec); 1522 psFree(yVec); 1523 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1524 return(NULL); 1525 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); 1526 } 1527 psTrace(__func__, 4, "The intercepts are (%.2f, %.2f)\n", leftIntercept, rightIntercept); 1528 xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept; 1529 1530 // Set starting column for next row 1531 col = (psS32) ((leftIntercept + rightIntercept) / 2.0); 1532 } 1533 // 1534 // Start at the row (+1) with peak pixel, then increment. 1535 // 1536 col = source->peak->x; 1537 for (psS32 row = 1 + source->peak->y; row < source->pixels->numRows ; row++) { 1538 // XXX: yVec contain no real information. Do we really need it? 1539 yVec->data.F32[row] = (psF32) (source->pixels->row0 + row); 1540 yVec->data.F32[row+yVec->n] = (psF32) (source->pixels->row0 + row); 1541 1542 // Starting at peak pixel, search leftwards for the column intercept. 1543 psF32 leftIntercept = findValue(source, level, row, col, 0); 1544 if (isnan(leftIntercept)) { 1545 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)"); 1546 psFree(xVec); 1547 psFree(yVec); 1548 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1549 return(NULL); 1550 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); 1551 } 1552 xVec->data.F32[row] = ((psF32) source->pixels->col0) + leftIntercept; 1553 1554 // Starting at peak pixel, search rightwards for the column intercept. 1555 psF32 rightIntercept = findValue(source, level, row, col, 1); 1556 if (isnan(rightIntercept)) { 1557 psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)"); 1558 psFree(xVec); 1559 psFree(yVec); 1560 psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__); 1561 return(NULL); 1562 //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n"); 1563 } 1564 xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept; 1565 1566 // Set starting column for next row 1567 col = (psS32) ((leftIntercept + rightIntercept) / 2.0); 1568 } 1569 1570 // 1571 // Allocate an array for result, store coord vectors there. 1572 // 1573 psArray *tmpArray = psArrayAlloc(2); 1574 tmpArray->data[0] = (psPtr *) yVec; 1575 tmpArray->data[1] = (psPtr *) xVec; 1576 psTrace(__func__, 3, "---- %s() end ----\n", __func__); 1577 return(tmpArray); 1578 } 1579 1580 // save a static values so they may be set externally 1581 static psF32 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = 15; 1582 static psF32 PM_SOURCE_FIT_MODEL_TOLERANCE = 0.1; 1583 1584 bool pmSourceFitModelInit (float nIter, float tol) 1585 { 1586 1587 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = nIter; 1588 PM_SOURCE_FIT_MODEL_TOLERANCE = tol; 1589 return true; 1590 } 1591 1592 bool pmSourceFitModel (pmSource *source, 1593 pmModel *model, 1594 const bool PSF) 1595 { 1596 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1597 PS_ASSERT_PTR_NON_NULL(source, false); 1598 PS_ASSERT_PTR_NON_NULL(source->moments, false); 1599 PS_ASSERT_PTR_NON_NULL(source->peak, false); 1600 PS_ASSERT_PTR_NON_NULL(source->pixels, false); 1601 PS_ASSERT_PTR_NON_NULL(source->mask, false); 1602 PS_ASSERT_PTR_NON_NULL(source->weight, false); 1603 1604 // XXX EAM : is it necessary for the mask & weight to exist? the 1605 // tests below could be conditions (!NULL) 1606 1607 psBool fitStatus = true; 1608 psBool onPic = true; 1609 psBool rc = true; 1610 1611 psVector *params = model->params; 1612 psVector *dparams = model->dparams; 1613 psVector *paramMask = NULL; 1614 1615 pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type); 1616 1617 int nParams = PSF ? 4 : params->n; 1618 1619 // maximum number of valid pixels 1620 psS32 nPix = source->pixels->numRows * source->pixels->numCols; 1621 1622 // construct the coordinate and value entries 1623 psArray *x = psArrayAlloc(nPix); 1624 psVector *y = psVectorAlloc(nPix, PS_TYPE_F32); 1625 psVector *yErr = psVectorAlloc(nPix, PS_TYPE_F32); 1626 1627 nPix = 0; 1628 for (psS32 i = 0; i < source->pixels->numRows; i++) { 1629 for (psS32 j = 0; j < source->pixels->numCols; j++) { 1630 if (source->mask->data.U8[i][j]) { 1631 continue; 1632 } 1633 psVector *coord = psVectorAlloc(2, PS_TYPE_F32); 1634 1635 // Convert i/j to image space: 1636 coord->data.F32[0] = (psF32) (j + source->pixels->col0); 1637 coord->data.F32[1] = (psF32) (i + source->pixels->row0); 1638 x->data[nPix] = (psPtr *) coord; 1639 y->data.F32[nPix] = source->pixels->data.F32[i][j]; 1640 1641 // psMinimizeLMChi2 takes wt = 1/dY^2 1642 if (source->weight->data.F32[i][j] == 0) { 1643 continue; 1644 } 1645 yErr->data.F32[nPix] = 1.0 / source->weight->data.F32[i][j]; 1646 nPix++; 1647 } 1648 } 1649 if (nPix < nParams + 1) { 1650 psTrace (".pmObjects.pmSourceFitModel", 4, "insufficient valid pixels\n"); 1651 psTrace(__func__, 3, "---- %s(false) end ----\n", __func__); 1652 model->status = PM_MODEL_BADARGS; 1653 psFree (x); 1654 psFree (y); 1655 psFree (yErr); 1656 return(false); 1657 } 1658 x->n = nPix; 1659 y->n = nPix; 1660 yErr->n = nPix; 1661 1662 psMinimization *myMin = psMinimizationAlloc(PM_SOURCE_FIT_MODEL_NUM_ITERATIONS, 1663 PM_SOURCE_FIT_MODEL_TOLERANCE); 1664 1665 // PSF model only fits first 4 parameters, EXT model fits all 1666 if (PSF) { 1667 paramMask = psVectorAlloc (params->n, PS_TYPE_U8); 1668 for (int i = 0; i < 4; i++) { 1669 paramMask->data.U8[i] = 0; 1670 } 1671 for (int i = 4; i < paramMask->n; i++) { 1672 paramMask->data.U8[i] = 1; 1673 } 1674 } 1675 1676 // Set the parameter range checks 1677 pmModelLimits modelLimits = pmModelLimits_GetFunction (model->type); 1678 psVector *beta_lim = NULL; 1679 psVector *params_min = NULL; 1680 psVector *params_max = NULL; 1681 1682 // XXX EAM : in this implementation, I pass in the limits with the covar matrix. 1683 // in the SDRS, I define a new psMinimization which will take these in 1684 psImage *covar = psImageAlloc (params->n, 3, PS_TYPE_F64); 1685 modelLimits (&beta_lim, ¶ms_min, ¶ms_max); 1686 for (int i = 0; i < params->n; i++) { 1687 covar->data.F64[0][i] = beta_lim->data.F32[i]; 1688 covar->data.F64[1][i] = params_min->data.F32[i]; 1689 covar->data.F64[2][i] = params_max->data.F32[i]; 1690 } 1691 1692 psTrace (".pmObjects.pmSourceFitModel", 5, "fitting function\n"); 1693 fitStatus = psMinimizeLMChi2(myMin, covar, params, paramMask, x, y, yErr, modelFunc); 1694 for (int i = 0; i < dparams->n; i++) { 1695 if ((paramMask != NULL) && paramMask->data.U8[i]) 1696 continue; 1697 dparams->data.F32[i] = sqrt(covar->data.F64[i][i]); 1698 } 1699 1700 // save the resulting chisq, nDOF, nIter 1701 model->chisq = myMin->value; 1702 model->nIter = myMin->iter; 1703 model->nDOF = y->n - nParams; 1704 1705 // get the Gauss-Newton distance for fixed model parameters 1706 if (paramMask != NULL) { 1707 psVector *delta = psVectorAlloc (params->n, PS_TYPE_F64); 1708 psMinimizeGaussNewtonDelta(delta, params, NULL, x, y, yErr, modelFunc); 1681 1709 for (int i = 0; i < dparams->n; i++) { 1682 if ( (paramMask != NULL) &¶mMask->data.U8[i])1710 if (!paramMask->data.U8[i]) 1683 1711 continue; 1684 dparams->data.F32[i] = sqrt(covar->data.F64[i][i]); 1685 } 1686 1687 // save the resulting chisq, nDOF, nIter 1688 model->chisq = myMin->value; 1689 model->nIter = myMin->iter; 1690 model->nDOF = y->n - nParams; 1691 1692 // get the Gauss-Newton distance for fixed model parameters 1693 if (paramMask != NULL) { 1694 psVector *delta = psVectorAlloc (params->n, PS_TYPE_F64); 1695 psMinimizeGaussNewtonDelta(delta, params, NULL, x, y, yErr, modelFunc); 1696 for (int i = 0; i < dparams->n; i++) { 1697 if (!paramMask->data.U8[i]) 1698 continue; 1699 dparams->data.F32[i] = delta->data.F64[i]; 1700 } 1701 } 1702 1703 // set the model success or failure status 1704 if (!fitStatus) { 1705 model->status = PM_MODEL_NONCONVERGE; 1706 } else { 1707 model->status = PM_MODEL_SUCCESS; 1708 } 1709 1710 // models can go insane: reject these 1711 onPic &= (params->data.F32[2] >= source->pixels->col0); 1712 onPic &= (params->data.F32[2] < source->pixels->col0 + source->pixels->numCols); 1713 onPic &= (params->data.F32[3] >= source->pixels->row0); 1714 onPic &= (params->data.F32[3] < source->pixels->row0 + source->pixels->numRows); 1715 if (!onPic) { 1716 model->status = PM_MODEL_OFFIMAGE; 1717 } 1718 1719 source->mode |= PM_SOURCE_FITTED; 1720 1721 psFree(x); 1722 psFree(y); 1723 psFree(yErr); 1724 psFree(myMin); 1725 psFree(covar); 1726 psFree(paramMask); 1727 1728 rc = (onPic && fitStatus); 1729 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1730 return(rc); 1731 } 1732 1733 bool p_pmSourceAddOrSubModel(psImage *image, 1734 psImage *mask, 1735 pmModel *model, 1736 bool center, 1737 bool sky, 1738 bool add 1739 ) { 1740 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1741 1742 PS_ASSERT_PTR_NON_NULL(model, false); 1743 PS_ASSERT_IMAGE_NON_NULL(image, false); 1744 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 1745 1746 psVector *x = psVectorAlloc(2, PS_TYPE_F32); 1747 psVector *params = model->params; 1748 pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type); 1749 psS32 imageCol; 1750 psS32 imageRow; 1751 psF32 skyValue = params->data.F32[0]; 1752 psF32 pixelValue; 1753 1754 for (psS32 i = 0; i < image->numRows; i++) { 1755 for (psS32 j = 0; j < image->numCols; j++) { 1756 if ((mask != NULL) && mask->data.U8[i][j]) 1757 continue; 1758 1759 // XXX: Should you be adding the pixels for the entire subImage, 1760 // or a radius of pixels around it? 1761 1762 // Convert i/j to imace coord space: 1763 // XXX: Make sure you have col/row order correct. 1764 // XXX EAM : 'center' option changes this 1765 // XXX EAM : i == numCols/2 -> x = model->params->data.F32[2] 1766 if (center) { 1767 imageCol = j - 0.5*image->numCols + model->params->data.F32[2]; 1768 imageRow = i - 0.5*image->numRows + model->params->data.F32[3]; 1769 } else { 1770 imageCol = j + image->col0; 1771 imageRow = i + image->row0; 1772 } 1773 1774 x->data.F32[0] = (float) imageCol; 1775 x->data.F32[1] = (float) imageRow; 1776 1777 // set the appropriate pixel value for this coordinate 1778 if (sky) { 1779 pixelValue = modelFunc (NULL, params, x); 1780 } else { 1781 pixelValue = modelFunc (NULL, params, x) - skyValue; 1782 } 1783 1784 1785 // add or subtract the value 1786 if (add 1787 ) { 1788 image->data.F32[i][j] += pixelValue; 1789 } 1790 else { 1791 image->data.F32[i][j] -= pixelValue; 1792 } 1793 } 1794 } 1795 psFree(x); 1796 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 1797 return(true); 1798 } 1799 1800 1801 1802 /****************************************************************************** 1803 *****************************************************************************/ 1804 bool pmSourceAddModel(psImage *image, 1805 psImage *mask, 1806 pmModel *model, 1807 bool center, 1808 bool sky) { 1809 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1810 psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, sky, true); 1811 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1812 return(rc); 1813 } 1814 1815 /****************************************************************************** 1816 *****************************************************************************/ 1817 bool pmSourceSubModel(psImage *image, 1818 psImage *mask, 1819 pmModel *model, 1820 bool center, 1821 bool sky) { 1822 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1823 psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, sky, false); 1824 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1825 return(rc); 1826 } 1827 1828 bool pmSourcePhotometry (float *fitMag, float *obsMag, pmModel *model, psImage *image, psImage *mask) { 1829 1830 float obsSum = 0; 1831 float fitSum = 0; 1832 float sky = model->params->data.F32[0]; 1833 1834 pmModelFlux modelFluxFunc = pmModelFlux_GetFunction (model->type); 1835 fitSum = modelFluxFunc (model->params); 1836 1837 for (int ix = 0; ix < image->numCols; ix++) { 1838 for (int iy = 0; iy < image->numRows; iy++) { 1839 if (mask->data.U8[iy][ix]) 1840 continue; 1841 obsSum += image->data.F32[iy][ix] - sky; 1842 } 1843 } 1844 if (obsSum <= 0) 1845 return false; 1846 if (fitSum <= 0) 1847 return false; 1848 1849 *fitMag = -2.5*log10(fitSum); 1850 *obsMag = -2.5*log10(obsSum); 1851 return (true); 1852 } 1853 1712 dparams->data.F32[i] = delta->data.F64[i]; 1713 } 1714 } 1715 1716 // set the model success or failure status 1717 if (!fitStatus) { 1718 model->status = PM_MODEL_NONCONVERGE; 1719 } else { 1720 model->status = PM_MODEL_SUCCESS; 1721 } 1722 1723 // models can go insane: reject these 1724 onPic &= (params->data.F32[2] >= source->pixels->col0); 1725 onPic &= (params->data.F32[2] < source->pixels->col0 + source->pixels->numCols); 1726 onPic &= (params->data.F32[3] >= source->pixels->row0); 1727 onPic &= (params->data.F32[3] < source->pixels->row0 + source->pixels->numRows); 1728 if (!onPic) { 1729 model->status = PM_MODEL_OFFIMAGE; 1730 } 1731 1732 source->mode |= PM_SOURCE_FITTED; 1733 1734 psFree(x); 1735 psFree(y); 1736 psFree(yErr); 1737 psFree(myMin); 1738 psFree(covar); 1739 psFree(paramMask); 1740 1741 rc = (onPic && fitStatus); 1742 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1743 return(rc); 1744 } 1745 1746 bool p_pmSourceAddOrSubModel(psImage *image, 1747 psImage *mask, 1748 pmModel *model, 1749 bool center, 1750 bool sky, 1751 bool add 1752 ) 1753 { 1754 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1755 1756 PS_ASSERT_PTR_NON_NULL(model, false); 1757 PS_ASSERT_IMAGE_NON_NULL(image, false); 1758 PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false); 1759 1760 psVector *x = psVectorAlloc(2, PS_TYPE_F32); 1761 psVector *params = model->params; 1762 pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type); 1763 psS32 imageCol; 1764 psS32 imageRow; 1765 psF32 skyValue = params->data.F32[0]; 1766 psF32 pixelValue; 1767 1768 for (psS32 i = 0; i < image->numRows; i++) { 1769 for (psS32 j = 0; j < image->numCols; j++) { 1770 if ((mask != NULL) && mask->data.U8[i][j]) 1771 continue; 1772 1773 // XXX: Should you be adding the pixels for the entire subImage, 1774 // or a radius of pixels around it? 1775 1776 // Convert i/j to imace coord space: 1777 // XXX: Make sure you have col/row order correct. 1778 // XXX EAM : 'center' option changes this 1779 // XXX EAM : i == numCols/2 -> x = model->params->data.F32[2] 1780 if (center) { 1781 imageCol = j - 0.5*image->numCols + model->params->data.F32[2]; 1782 imageRow = i - 0.5*image->numRows + model->params->data.F32[3]; 1783 } else { 1784 imageCol = j + image->col0; 1785 imageRow = i + image->row0; 1786 } 1787 1788 x->data.F32[0] = (float) imageCol; 1789 x->data.F32[1] = (float) imageRow; 1790 1791 // set the appropriate pixel value for this coordinate 1792 if (sky) { 1793 pixelValue = modelFunc (NULL, params, x); 1794 } else { 1795 pixelValue = modelFunc (NULL, params, x) - skyValue; 1796 } 1797 1798 1799 // add or subtract the value 1800 if (add 1801 ) { 1802 image->data.F32[i][j] += pixelValue; 1803 } 1804 else { 1805 image->data.F32[i][j] -= pixelValue; 1806 } 1807 } 1808 } 1809 psFree(x); 1810 psTrace(__func__, 3, "---- %s(true) end ----\n", __func__); 1811 return(true); 1812 } 1813 1814 1815 1816 /****************************************************************************** 1817 *****************************************************************************/ 1818 bool pmSourceAddModel(psImage *image, 1819 psImage *mask, 1820 pmModel *model, 1821 bool center, 1822 bool sky) 1823 { 1824 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1825 psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, sky, true); 1826 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1827 return(rc); 1828 } 1829 1830 /****************************************************************************** 1831 *****************************************************************************/ 1832 bool pmSourceSubModel(psImage *image, 1833 psImage *mask, 1834 pmModel *model, 1835 bool center, 1836 bool sky) 1837 { 1838 psTrace(__func__, 3, "---- %s() begin ----\n", __func__); 1839 psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, sky, false); 1840 psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc); 1841 return(rc); 1842 } 1843 1844 bool pmSourcePhotometry (float *fitMag, float *obsMag, pmModel *model, psImage *image, psImage *mask) 1845 { 1846 1847 float obsSum = 0; 1848 float fitSum = 0; 1849 float sky = model->params->data.F32[0]; 1850 1851 pmModelFlux modelFluxFunc = pmModelFlux_GetFunction (model->type); 1852 fitSum = modelFluxFunc (model->params); 1853 1854 for (int ix = 0; ix < image->numCols; ix++) { 1855 for (int iy = 0; iy < image->numRows; iy++) { 1856 if (mask->data.U8[iy][ix]) 1857 continue; 1858 obsSum += image->data.F32[iy][ix] - sky; 1859 } 1860 } 1861 if (obsSum <= 0) 1862 return false; 1863 if (fitSum <= 0) 1864 return false; 1865 1866 *fitMag = -2.5*log10(fitSum); 1867 *obsMag = -2.5*log10(obsSum); 1868 return (true); 1869 } 1870 -
branches/eam_rel9_p0/psModules/src/objects/pmObjects.h
r6182 r6183 10 10 * @author GLG, MHPCC 11 11 * 12 * @version $Revision: 1.4.4. 5$ $Name: not supported by cvs2svn $13 * @date $Date: 2006-01-22 2 0:20:47$12 * @version $Revision: 1.4.4.6 $ $Name: not supported by cvs2svn $ 13 * @date $Date: 2006-01-22 21:12:20 $ 14 14 * 15 15 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 476 476 477 477 bool pmSourceFitModelInit( 478 float nIter ;///< max number of allowed iterations479 float tol ///< convergence criterion478 float nIter, ///< max number of allowed iterations 479 float tol ///< convergence criterion 480 480 ); 481 481
Note:
See TracChangeset
for help on using the changeset viewer.
