Changeset 2197 for trunk/psLib/src/dataManip/psStats.c
- Timestamp:
- Oct 26, 2004, 11:25:59 AM (22 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/dataManip/psStats.c (modified) (29 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/dataManip/psStats.c
r2074 r2197 9 9 * @author GLG, MHPCC 10 10 * 11 * @version $Revision: 1.6 7$ $Name: not supported by cvs2svn $12 * @date $Date: 2004-10- 13 02:40:13 $11 * @version $Revision: 1.68 $ $Name: not supported by cvs2svn $ 12 * @date $Date: 2004-10-26 21:24:43 $ 13 13 * 14 14 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 40 40 /*****************************************************************************/ 41 41 // will use robust statistical methods. 42 #define GAUSS_WIDTH 20// The width of the Gaussian or boxcar smoothing.42 #define GAUSS_WIDTH 5 // The width of the Gaussian or boxcar smoothing. 43 43 #define CLIPPED_NUM_ITER_LB 1 44 44 #define CLIPPED_NUM_ITER_UB 10 … … 57 57 /* TYPE DEFINITIONS */ 58 58 /*****************************************************************************/ 59 psVector* p_psConvertToF32(psVector* in); 59 60 60 61 /*****************************************************************************/ … … 423 424 float rangeMax = 0.0; // Exclude date above this 424 425 425 // Determine if the number of data points exceed a threshold which will426 // cause to generate robust stats, as opposed to exact stats.427 // XXX: This code is no longer used. We now calculate the median exactly428 // regardless of the vector size.429 /*430 * // Calculate the robust quartiles. stats2 = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);431 * p_psVectorRobustStats(myVector, maskVector, maskVal, stats2);432 *433 * // Store the robust quartiles into the sample quartile members. stats->sampleMedian =434 * stats2->robustMedian;435 *436 * // Free temporary data buffers. psFree(stats2);437 *438 * // Set the PS_STAT_ROBUST_FOR_SAMPLE bit in the stats structure. stats->options = stats->options |439 * PS_STAT_ROBUST_FOR_SAMPLE;440 *441 * return; } */442 443 426 // Determine how many data points fit inside this min/max range 444 427 // and are not masked, IF the maskVector is not NULL> … … 507 490 508 491 /****************************************************************************** 509 This routine smoothes the data in the input robustHistogram with a 510 Gaussian of width sigma. 511 512 XXX: Must consult with IfA on the proper values for the Gaussian 513 smoothing. Currently, the Gaussian coefficients are such that only 514 the center coefficient is non-zero. This is because "e" is being 515 raised to a very large negative number for all points except the 516 center point. 517 518 XXX: use a static variable for gaussianCoefs[] and compute them once. 519 *****************************************************************************/ 520 psVector* p_psVectorsmoothHistGaussian(psHistogram* robustHistogram, 492 p_psVectorSmoothHistGaussian(): This routine smoothes the data in the input 493 robustHistogram with a Gaussian of width sigma. 494 *****************************************************************************/ 495 #define GAUSS_WIDTH_OTHER 5.0 496 psVector* p_psVectorSmoothHistGaussian(psHistogram* robustHistogram, 521 497 float sigma) 522 498 { 523 499 int i = 0; // Loop index variable 524 500 int j = 0; // Loop index variable 525 float denom = 0.0; // Temporary variable 526 float expo = 0.0; // Temporary variable 527 float gaussianCoefs[1 + (2 * GAUSS_WIDTH)]; // The Gaussian Coefficients 528 psVector* smooth = psVectorAlloc(robustHistogram->nums->n, PS_TYPE_F32); 529 530 for (i = 0; i < (1 + (2 * GAUSS_WIDTH)); i++) { 531 if (fabs(sigma) >= FLT_EPSILON) { 532 // If sigma does not equal zero, then we use Gaussian smoothing. 533 #ifdef DARWIN 534 denom = (float)sqrt(2.0 * M_PI * sigma * sigma); 535 #else 536 537 denom = sqrtf(2.0 * M_PI * sigma * sigma); 538 #endif 539 540 expo = -(float)((i - GAUSS_WIDTH) * (i - GAUSS_WIDTH)); 541 expo /= (2.0 * sigma * sigma); 542 gaussianCoefs[i] = exp(expo / denom); 543 544 //printf("p_psVectorsmoothHistGaussian(): gaussianCoefs[%d] is %f\n", i, gaussianCoefs[i]); 545 // NOTE: Gaussian smoothing just isn't working with low sigma 546 // values. The problem is that the Gaussian coefficients are 547 // all zero, except for the middle coefficient, which is exactly 548 // one. Therefore, I'm using boxcar smoothing. 549 gaussianCoefs[i] = 1.0 / (1.0 + (2.0 * (float)GAUSS_WIDTH)); 550 // printf("gaussianCoefs[%d] is %f\n", i, gaussianCoefs[i]); 551 } else { 552 /* If sigma equals zero (all pixels have the same value) the above code will divide by zero. 553 * Therefore, we don't need to smooth the data. */ 554 for (i = 0; i < robustHistogram->nums->n; i++) { 555 smooth->data.F32[i] = (float)robustHistogram->nums->data.S32[i]; 556 } 557 return (smooth); 558 } 559 } 560 561 // Perform the actual smoothing. 562 for (i = 0; i < robustHistogram->nums->n; i++) { 501 float iMid; 502 float jMid; 503 int numBins = robustHistogram->nums->n; 504 int numBounds = robustHistogram->bounds->n; 505 psVector* smooth = psVectorAlloc(numBins, PS_TYPE_F32); 506 int jMin = 0; 507 int jMax = 0; 508 float firstBound = robustHistogram->bounds->data.F32[0]; 509 float lastBound = robustHistogram->bounds->data.F32[numBounds-1]; 510 psScalar x; 511 512 x.type.type = PS_TYPE_F32; 513 for (i = 0; i < numBins; i++) { 514 iMid = (robustHistogram->bounds->data.F32[i] + 515 robustHistogram->bounds->data.F32[i+1]) / 2.0; 516 517 // YYY: The p_psVectorBinDisect() routine does much of the work of 518 // the following conditionals, however, it also reports a warning 519 // message. I don't want the warning message so I reproduce the 520 // conditionals here. Maybe p_psVectorBinDisect() should not produce 521 // warnings? 522 523 x.data.F32 = iMid - (GAUSS_WIDTH * sigma); 524 if ((x.data.F32 >= firstBound) && (x.data.F32 <= lastBound)) { 525 jMin = p_psVectorBinDisect(robustHistogram->bounds, &x); 526 } else if (x.data.F32 <= firstBound) { 527 jMin = 0; 528 } else if (x.data.F32 >= lastBound) { 529 jMin = robustHistogram->bounds->n - 1; 530 531 } 532 533 x.data.F32 = iMid + (GAUSS_WIDTH * sigma); 534 if ((x.data.F32 >= firstBound) && (x.data.F32 <= lastBound)) { 535 jMax = p_psVectorBinDisect(robustHistogram->bounds, &x); 536 } else if (x.data.F32 <= firstBound) { 537 jMax = 0; 538 } else if (x.data.F32 >= lastBound) { 539 jMax = robustHistogram->bounds->n - 1; 540 541 } 542 563 543 smooth->data.F32[i] = 0.0; 564 for (j = -GAUSS_WIDTH; j <= +GAUSS_WIDTH; j++) { 565 if (((j + i) >= 0) && ((j + i) < smooth->n)) { 566 smooth->data.F32[i] += (gaussianCoefs[j + GAUSS_WIDTH] * 567 (float)robustHistogram->nums->data.S32[j + i]); 568 } 569 } 570 } 571 return (smooth); 544 for (j = jMin ; j <= jMax ; j++) { 545 jMid = (robustHistogram->bounds->data.F32[j] + 546 robustHistogram->bounds->data.F32[j+1]) / 2.0; 547 smooth->data.F32[i] += 548 ((float) robustHistogram->nums->data.U32[j]) * 549 psGaussian(jMid, iMid, sigma, true); 550 } 551 } 552 553 return(smooth); 572 554 } 573 555 … … 913 895 specified data point. 914 896 *****************************************************************************/ 915 float p_psGaussian(const psVector* restrict myData, const psVector* restrict myParams) 897 float p_psGaussian(const psVector* restrict myData, 898 const psVector* restrict myParams) 916 899 { 917 900 float x = myData->data.F32[0]; … … 930 913 calculates the specified partial derivative of the above Gaussian function. 931 914 *****************************************************************************/ 932 float p_psGaussianDeriv(const psVector* restrict myData, const psVector* restrict myParams, int whichParam) 915 float p_psGaussianDeriv(const psVector* restrict myData, 916 const psVector* restrict myParams, int whichParam) 933 917 { 934 918 float x = myData->data.F32[0]; … … 1036 1020 1037 1021 /****************************************************************************** 1038 p_psFitQuadratic(robustHistogram. cumulativeSums, binNum, fitFloat): given 1039 the specified histogram, with the specified pre-calculated cumulativeSums, 1040 this routine fits a quadratic f(x) to the 3 bins surrounding bin "binNum", 1041 and then finds the point x such that f(x) == fitFloat. 1022 fitQuadraticSearchForYThenReturnX(*xVec, *yVec, binNum, yVal): This routine 1023 takes psVectors of x/y pairs as input, and fits a quadratic to the 3 points 1024 surrounding element binNum in the vectors (the midpoint between element i 1025 and i+1 is used for x[i]). It then determines for what value x does that 1026 quadratic f(x) = yVal (the input parameter). 1042 1027 1043 XXX: This function is currently not being used. 1044 *****************************************************************************/ 1045 float p_psFitQuadratic(psHistogram* histogram, 1046 psVector* cumulativeSums, 1047 int binNum, 1048 float fitFloat) 1049 { 1028 // XXX: Use static variables. 1029 *****************************************************************************/ 1030 float fitQuadraticSearchForYThenReturnX(psVector *xVec, 1031 psVector *yVec, 1032 int binNum, 1033 float yVal) 1034 { 1035 // static psVector* x = NULL; 1036 // static psVector* y = NULL; 1037 // static psVector* yErr = NULL; 1050 1038 psVector* x = psVectorAlloc(3, PS_TYPE_F64); 1051 1039 psVector* y = psVectorAlloc(3, PS_TYPE_F64); 1052 1040 psVector* yErr = psVectorAlloc(3, PS_TYPE_F64); 1041 1042 /* 1043 if (x == NULL) { 1044 x = psVectorAlloc(3, PS_TYPE_F64); 1045 p_psMemSetPersistent(x, true); 1046 } 1047 if (y == NULL) { 1048 y = psVectorAlloc(3, PS_TYPE_F64); 1049 p_psMemSetPersistent(y, true); 1050 } 1051 if (yErr == NULL) { 1052 yErr = psVectorAlloc(3, PS_TYPE_F64); 1053 p_psMemSetPersistent(yErr, true); 1054 } 1055 */ 1053 1056 psPolynomial1D* myPoly = psPolynomial1DAlloc(2, PS_POLYNOMIAL_ORD); 1054 1055 if ((binNum > 0) && (binNum < (histogram->nums->n + 1))) { 1056 x->data.F64[0] = (double)0.5 * 1057 (histogram->bounds->data.F32[binNum - 1] + histogram->bounds->data.F32[binNum]); 1058 x->data.F64[1] = (double)0.5 * 1059 (histogram->bounds->data.F32[binNum] + histogram->bounds->data.F32[binNum + 1]); 1060 x->data.F64[2] = (double)0.5 * 1061 (histogram->bounds->data.F32[binNum + 1] + histogram->bounds->data.F32[binNum + 2]); 1062 1063 y->data.F64[0] = cumulativeSums->data.F32[binNum - 1]; 1064 y->data.F64[1] = cumulativeSums->data.F32[binNum]; 1065 y->data.F64[2] = cumulativeSums->data.F32[binNum + 1]; 1066 1067 if (!((y->data.F64[0] <= fitFloat) && (fitFloat <= y->data.F64[2]))) { 1068 psAbort(__func__, "p_psVectorRobustStats(0): midpoint not within y-range\n"); 1069 } 1070 1057 float tmpFloat; 1058 1059 if ((binNum > 0) && (binNum < (yVec->n - 2))) { 1060 x->data.F64[0] = (double) (0.5 * (xVec->data.F32[binNum - 1] + xVec->data.F32[binNum])); 1061 x->data.F64[1] = (double) (0.5 * (xVec->data.F32[binNum] + xVec->data.F32[binNum+1])); 1062 x->data.F64[2] = (double) (0.5 * (xVec->data.F32[binNum+1] + xVec->data.F32[binNum+2])); 1063 y->data.F64[0] = yVec->data.F32[binNum - 1]; 1064 y->data.F64[1] = yVec->data.F32[binNum]; 1065 y->data.F64[2] = yVec->data.F32[binNum + 1]; 1066 1067 // Ensure that yVal is within the range of the bins we are using. 1068 if (!((y->data.F64[0] <= yVal) && (yVal <= y->data.F64[2]))) { 1069 printf("((%f), %f, %f)\n", yVal, y->data.F64[0], y->data.F64[2]); 1070 psError(__func__, "yVal not within y-range\n"); 1071 } 1071 1072 yErr->data.F64[0] = 1.0; 1072 1073 yErr->data.F64[1] = 1.0; 1073 1074 yErr->data.F64[2] = 1.0; 1074 1075 1076 // Determine the coefficients of the polynomial. 1075 1077 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1076 return (p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], fitFloat)); 1078 // Call p_ps1DPolyMedian(), which does a binary search on the 1079 // polynomial, looking for the value x such that f(x) = yVal 1080 tmpFloat = p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], yVal); 1077 1081 } else { 1078 return (0.5 * (histogram->bounds->data.F32[binNum + 1] + histogram->bounds->data.F32[binNum])); 1082 if (binNum == 0) { 1083 tmpFloat = 0.5 * (xVec->data.F32[binNum] + 1084 xVec->data.F32[binNum + 1]); 1085 } else if (binNum == (xVec->n - 1)) { 1086 // XXX: Is this right? 1087 tmpFloat = xVec->data.F32[binNum]; 1088 } else if (binNum == (xVec->n - 2)) { 1089 // XXX: Is this right? 1090 tmpFloat = 0.5 * (xVec->data.F32[binNum] + 1091 xVec->data.F32[binNum + 1]); 1092 } 1079 1093 } 1080 1094 … … 1083 1097 psFree(yErr); 1084 1098 psFree(myPoly); 1085 return (0.0); 1086 } 1099 return(tmpFloat); 1100 } 1101 1102 #define PS_BIN_MIDPOINT(HISTOGRAM, BIN_NUM) \ 1103 (0.5 * (HISTOGRAM->bounds->data.F32[(BIN_NUM)] + HISTOGRAM->bounds->data.F32[(BIN_NUM)+1])) 1087 1104 1088 1105 /****************************************************************************** … … 1111 1128 *****************************************************************************/ 1112 1129 void p_psVectorRobustStats(const psVector* restrict myVector, 1113 const psVector* restrict maskVector, unsigned int maskVal, psStats* stats) 1130 const psVector* restrict maskVector, 1131 unsigned int maskVal, 1132 psStats* stats) 1114 1133 { 1115 1134 psHistogram* robustHistogram = NULL; … … 1118 1137 int LQBinNum = -1; // Bin num for lower quartile 1119 1138 int UQBinNum = -1; // Bin num for upper quartile 1139 int medianBinNum = -1; 1120 1140 int i = 0; // Loop index variable 1121 int m axBinNum = 0;1122 float m axBinCount = 0.0;1141 int modeBinNum = 0; 1142 float modeBinCount = 0.0; 1123 1143 float dL = 0.0; 1124 1144 int numBins = 0; 1125 psStats* tmpStats = psStatsAlloc(PS_STAT_CLIPPED_STDEV | PS_STAT_CLIPPED_MEAN);1126 1127 // psImage* domain;1128 // psVector* errors;1129 // psVector* data;1130 // psVector* initialGuess;1131 // psVector* theParams;1132 // float chiSq=0.0;1133 // float max = -HUGE;1134 // float max_pos;1135 1145 float myMean = 0.0; 1136 1146 float myStdev = 0.0; … … 1139 1149 float sumSquares = 0.0; 1140 1150 float sumDiffs = 0.0; 1141 psVector* x = psVectorAlloc(3, PS_TYPE_F64); 1142 psVector* y = psVectorAlloc(3, PS_TYPE_F64); 1143 psVector* yErr = psVectorAlloc(3, PS_TYPE_F64); 1144 psPolynomial1D* myPoly = psPolynomial1DAlloc(2, PS_POLYNOMIAL_ORD); 1145 psVector* cumulativeRobustSumsFullRange = NULL; 1146 psVector* cumulativeRobustSumsDlRange = NULL; 1151 psVector* cumulativeRobustSums = NULL; 1147 1152 float sumRobust = 0.0; 1148 1153 float sumN50 = 0.0; 1149 1154 float sumNfit = 0.0; 1150 float cumulativeMedian = 0.0; 1155 psScalar tmpScalar; 1156 tmpScalar.type.type = PS_TYPE_F32; 1157 psStats* tmpStats = psStatsAlloc(PS_STAT_CLIPPED_STDEV | PS_STAT_CLIPPED_MEAN); 1151 1158 1152 1159 // Compute the initial bin size of the robust histogram. This is done … … 1188 1195 p_psVectorMax(myVector, maskVector, maskVal, stats); 1189 1196 } 1197 1190 1198 // Create the histogram structure. NOTE: we can not specify the bin size 1191 1199 // precisely since the argument to psHistogramAlloc() is the number of … … 1198 1206 psVectorHistogram(robustHistogram, myVector, maskVector, maskVal); 1199 1207 1200 // Smooth the histogram. 1201 // XXX: is that the right stdev? 1202 robustHistogramVector = p_psVectorsmoothHistGaussian(robustHistogram, 1208 // Smooth the histogram, Gaussian-style. 1209 robustHistogramVector = p_psVectorSmoothHistGaussian(robustHistogram, 1203 1210 tmpStats->clippedStdev / 4.0f); 1204 1211 … … 1208 1215 1209 1216 /************************************************************************** 1210 Determine the lower/upper quartiles. 1217 Determine the median/lower/upper quartile bin numbers. 1218 1219 We define a vector called "cumulativeRobustSums" where the value at 1220 index position i is equal to the sum of bins 0:i. This will be used in 1221 determining the median and lower/upper quartiles. 1211 1222 **************************************************************************/ 1212 // We define a vector called "cumulativeRobustSums..." where the value at 1213 // index position i is equal to the sum of bins 0:i. This will be used 1214 // now and later in determining the lower/upper quartiles. 1215 cumulativeRobustSumsFullRange = psVectorAlloc(robustHistogramVector->n, PS_TYPE_F32); 1216 cumulativeRobustSumsFullRange->data.F32[0] = robustHistogramVector->data.F32[0]; 1223 cumulativeRobustSums = psVectorAlloc(robustHistogramVector->n, PS_TYPE_F32); 1224 cumulativeRobustSums->data.F32[0] = robustHistogramVector->data.F32[0]; 1217 1225 for (i = 1; i < robustHistogramVector->n; i++) { 1218 cumulativeRobustSumsFullRange->data.F32[i] = 1219 cumulativeRobustSumsFullRange->data.F32[i - 1] + robustHistogramVector->data.F32[i]; 1220 } 1221 sumRobust = cumulativeRobustSumsFullRange->data.F32[robustHistogramVector->n - 1]; 1222 1223 // Determine the bin number containing the lower quartile point. 1224 LQBinNum = -1; 1225 for (i = 0; i < cumulativeRobustSumsFullRange->n; i++) { 1226 if (cumulativeRobustSumsFullRange->data.F32[i] >= (sumRobust / 4.0)) { 1227 LQBinNum = i; 1228 break; 1229 } 1230 } 1231 1232 // Determine the bin number containing the upper quartile point. 1233 UQBinNum = -1; 1234 for (i = cumulativeRobustSumsFullRange->n - 1; i >= 0; i--) { 1235 if (cumulativeRobustSumsFullRange->data.F32[i] <= (3.0 * sumRobust / 4.0)) { 1236 UQBinNum = i; 1237 break; 1238 } 1239 } 1240 1241 if ((LQBinNum == -1) || (UQBinNum == -1)) { 1242 psAbort(__func__, "Could not determine the robust lower/upper quartiles."); 1243 } 1244 1226 cumulativeRobustSums->data.F32[i] = cumulativeRobustSums->data.F32[i - 1] + 1227 robustHistogramVector->data.F32[i]; 1228 } 1229 sumRobust = cumulativeRobustSums->data.F32[robustHistogramVector->n - 1]; 1230 1231 tmpScalar.data.F32 = sumRobust / 4.0; 1232 LQBinNum = p_psVectorBinDisect(cumulativeRobustSums, &tmpScalar); 1233 tmpScalar.data.F32 = 3.0 * sumRobust / 4.0; 1234 UQBinNum = p_psVectorBinDisect(cumulativeRobustSums, &tmpScalar); 1235 tmpScalar.data.F32 = sumRobust / 2.0; 1236 medianBinNum = p_psVectorBinDisect(cumulativeRobustSums, &tmpScalar); 1237 1238 if ((LQBinNum < 0) || (UQBinNum < 0)) { 1239 psError(__func__, "Could not determine the robust lower/upper quartile bin numbers."); 1240 } 1241 if (medianBinNum < 0) { 1242 psError(__func__, "Could not determine the robust lower/upper quartile bin numbers."); 1243 } 1245 1244 /************************************************************************** 1246 1245 Determine the mode in the range LQ:UQ. 1247 1246 **************************************************************************/ 1248 1247 // Determine the bin with the peak value in the range LQ to UQ. 1249 m axBinNum = LQBinNum;1250 m axBinCount = robustHistogramVector->data.F32[LQBinNum];1251 sumN50 = (float)robustHistogram->nums->data. S32[LQBinNum];1248 modeBinNum = LQBinNum; 1249 modeBinCount = robustHistogramVector->data.F32[LQBinNum]; 1250 sumN50 = (float)robustHistogram->nums->data.U32[LQBinNum]; 1252 1251 for (i = LQBinNum + 1; i <= UQBinNum; i++) { 1253 if (robustHistogramVector->data.F32[i] > maxBinCount) { 1254 maxBinNum = i; 1255 maxBinCount = robustHistogramVector->data.F32[i]; 1256 } 1257 sumN50 += (float)robustHistogram->nums->data.S32[i]; 1258 } 1259 1260 // XXX: is dL defined as the value at the LQ/UQ, or the bin number? 1252 if (robustHistogramVector->data.F32[i] > modeBinCount) { 1253 modeBinNum = i; 1254 modeBinCount = robustHistogramVector->data.F32[i]; 1255 } 1256 sumN50 += (float)robustHistogram->nums->data.U32[i]; 1257 } 1258 1261 1259 dL = (UQBinNum - LQBinNum) / 4; 1262 1263 printf("(LQBinNum, UQBinNum, maxBinNum) is (%d, %d, %d)\n", LQBinNum, UQBinNum, maxBinNum);1264 1265 1260 /************************************************************************** 1266 1261 Determine the mean/stdev for the bins in the range mode-dL to mode+dL 1267 1262 **************************************************************************/ 1268 cumulativeRobustSumsDlRange = psVectorAlloc(robustHistogramVector->n, PS_TYPE_F32);1269 for (i = 0; i < robustHistogramVector->n; i++) {1270 cumulativeRobustSumsDlRange->data.F32[i] = 0.0;1271 }1272 sumNfit = 0.0;1273 cumulativeMedian = 0.0;1274 for (i = maxBinNum - dL; i <= maxBinNum + dL; i++) {1275 if ((0 <= i) && (i < robustHistogramVector->n)) {1276 cumulativeRobustSumsDlRange->data.F32[i] =1277 cumulativeRobustSumsDlRange->data.F32[i - 1] + robustHistogramVector->data.F32[i];1278 cumulativeMedian += robustHistogramVector->data.F32[i];1279 sumNfit += (float)robustHistogram->nums->data.S32[i];1280 }1281 }1282 1283 1263 // Calculate the mean of the smoothed robust histogram in the range 1284 1264 // mode-dL to mode+dL. We use the midpoint of each bin as the mean for 1285 1265 // that bin (this is a non-exact approximation). 1266 sumNfit = 0.0; 1286 1267 myMean = 0.0; 1287 for (i = m axBinNum - dL; i <= maxBinNum + dL; i++) {1268 for (i = modeBinNum - dL; i <= modeBinNum + dL; i++) { 1288 1269 if ((0 <= i) && (i < robustHistogramVector->n)) { 1289 myMean += (robustHistogramVector->data.F32[i]) * 0.5 * 1290 (robustHistogram->bounds->data.F32[i + 1] + robustHistogram->bounds->data.F32[i]); 1270 myMean += (robustHistogramVector->data.F32[i]) * PS_BIN_MIDPOINT(robustHistogram, i); 1291 1271 countFloat += robustHistogramVector->data.F32[i]; 1292 1272 } 1273 1274 sumNfit += (float)robustHistogram->nums->data.U32[i]; 1293 1275 } 1294 1276 myMean /= countFloat; … … 1297 1279 // mode-dL to mode+dL. We use the midpoint of each bin as the mean for 1298 1280 // that bin. 1299 for (i = m axBinNum - dL; i <= maxBinNum + dL; i++) {1281 for (i = modeBinNum - dL; i <= modeBinNum + dL; i++) { 1300 1282 if ((0 <= i) && (i < robustHistogramVector->n)) { 1301 diff = (0.5 * (robustHistogram->bounds->data.F32[i + 1] + 1302 robustHistogram->bounds->data.F32[i])) - myMean; 1283 diff = PS_BIN_MIDPOINT(robustHistogram, i) - myMean; 1303 1284 sumSquares += diff * diff * robustHistogramVector->data.F32[i]; 1304 1285 sumDiffs += diff * robustHistogramVector->data.F32[i]; … … 1315 1296 1316 1297 if (stats->options & PS_STAT_ROBUST_MODE) { 1317 stats->robustMode = 0.5 * 1318 (robustHistogram->bounds->data.F32[maxBinNum] + robustHistogram->bounds->data.F32[maxBinNum + 1]); 1298 stats->robustMode = PS_BIN_MIDPOINT(robustHistogram, modeBinNum); 1319 1299 } 1320 1300 … … 1322 1302 stats->robustStdev = myStdev; 1323 1303 } 1324 // To determine the median (and later, the lower/upper quartile), we fit 1325 // a quadratic to the three bins surrounding the bin containing the median. 1326 // The quadratic y=f(x) with x being the midpoint of each bin, and y being 1327 // the cumulative number of data points in all bins up to, and including, 1328 // this bin. We then solve the quadratic for 1329 1330 // XXX: Create a "p_psQuadraticFitAndSolveForX() function. 1331 1304 1305 // To determine the median, we fit a quadratic y=f(x) to the three bins 1306 // surrounding the bin containing the median (x is the midpoint of each 1307 // bin and y is the value of each bin). Then we figure out what value 1308 // of x corresponds to f(x) being the median (half of all points). 1332 1309 if (stats->options & PS_STAT_ROBUST_MEDIAN) { 1333 if ((maxBinNum > 0) && (maxBinNum < (robustHistogram->nums->n - 1))) { 1334 x->data.F64[0] = (double)0.5 * 1335 (robustHistogram->bounds->data.F32[maxBinNum - 1] + 1336 robustHistogram->bounds->data.F32[maxBinNum]); 1337 x->data.F64[1] = (double)0.5 * 1338 (robustHistogram->bounds->data.F32[maxBinNum] + 1339 robustHistogram->bounds->data.F32[maxBinNum + 1]); 1340 x->data.F64[2] = (double)0.5 * 1341 (robustHistogram->bounds->data.F32[maxBinNum + 1] + 1342 robustHistogram->bounds->data.F32[maxBinNum + 2]); 1343 1344 y->data.F64[0] = cumulativeRobustSumsDlRange->data.F32[maxBinNum - 1]; 1345 y->data.F64[1] = cumulativeRobustSumsDlRange->data.F32[maxBinNum]; 1346 y->data.F64[2] = cumulativeRobustSumsDlRange->data.F32[maxBinNum + 1]; 1347 1348 // Ensure that cumulativeMedian/2 is actually within the range of the bins 1349 // we are using. 1350 cumulativeMedian *= 0.5; 1351 if (!((y->data.F64[0] <= cumulativeMedian) && (cumulativeMedian <= y->data.F64[2]))) { 1352 printf("((%f), %f, %f)\n", cumulativeMedian, y->data.F64[0], y->data.F64[2]); 1353 psAbort(__func__, "p_psVectorRobustStats(1): midpoint not within y-range\n"); 1354 } 1355 // XXX: yErr is not currently used by psVectorFitPolynomial1D(). We 1356 // may have to set this meaningfully later. 1357 yErr->data.F64[0] = 1.0; 1358 yErr->data.F64[1] = 1.0; 1359 yErr->data.F64[2] = 1.0; 1360 1361 // Determine the coefficients of the polynomial. 1362 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1363 // Call p_ps1DPolyMedian(), which does a binary search on the 1364 // polynomial, looking for the value x such that 1365 // f(x) = cumulativeMedian. 1366 stats->robustMedian = p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], cumulativeMedian); 1367 } else { 1368 // If the mode is the first/last histogram bin, then simply use 1369 // the midpoint of that bin. 1370 stats->robustMedian = 0.5 * (robustHistogram->bounds->data.F32[maxBinNum + 1] + 1371 robustHistogram->bounds->data.F32[maxBinNum]); 1372 } 1373 } 1374 // The lower/upper quartile calculations are very similar to the median 1375 // calculations. We fit a quadratic to the array containing the 1376 // cumulative data points in each bin, then search for x such that 1377 // f(x) equals the lower/upper quartile exactly. 1378 // 1310 // Take a psVector. Fit a polynomial y = f(x) to the 3 data elements 1311 // surrounding medianBinNum, then find the x-value corresponding y = sumRobust/2.0. 1312 stats->robustMedian = fitQuadraticSearchForYThenReturnX(robustHistogram->bounds, 1313 cumulativeRobustSums, 1314 medianBinNum, 1315 sumRobust/2.0); 1316 } 1317 1318 // To determine the quartiles, we fit a quadratic y=f(x) to the three bins 1319 // surrounding the bin containing LQ/UQ (x is the midpoint of each 1320 // bin and y is the value of each bin). Then we figure out what value 1321 // of x corresponds to f(x) being the LQ/UQ. 1379 1322 if (stats->options & PS_STAT_ROBUST_QUARTILE) { 1380 countFloat = cumulativeRobustSumsFullRange->data.F32[robustHistogramVector->n - 1]; 1381 1382 if ((LQBinNum > 0) && (LQBinNum < (robustHistogram->nums->n - 1))) { 1383 x->data.F64[0] = (double)0.5 * 1384 (robustHistogram->bounds->data.F32[LQBinNum - 1] + 1385 robustHistogram->bounds->data.F32[LQBinNum]); 1386 x->data.F64[1] = (double)0.5 * 1387 (robustHistogram->bounds->data.F32[LQBinNum] + 1388 robustHistogram->bounds->data.F32[LQBinNum + 1]); 1389 x->data.F64[2] = (double)0.5 * 1390 (robustHistogram->bounds->data.F32[LQBinNum + 1] + 1391 robustHistogram->bounds->data.F32[LQBinNum + 2]); 1392 1393 y->data.F64[0] = cumulativeRobustSumsFullRange->data.F32[LQBinNum - 1]; 1394 y->data.F64[1] = cumulativeRobustSumsFullRange->data.F32[LQBinNum]; 1395 y->data.F64[2] = cumulativeRobustSumsFullRange->data.F32[LQBinNum + 1]; 1396 1397 if (!((y->data.F64[0] <= (countFloat / 4.0)) && ((countFloat / 4.0) <= y->data.F64[2]))) { 1398 psAbort(__func__, "p_psVectorRobustStats(2): midpoint not within y-range\n"); 1399 } 1400 1401 yErr->data.F64[0] = 1.0; 1402 yErr->data.F64[1] = 1.0; 1403 yErr->data.F64[2] = 1.0; 1404 1405 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1406 stats->robustLQ = p_ps1DPolyMedian(myPoly, x->data.F64[0], x->data.F64[2], countFloat / 4.0); 1407 1408 } else { 1409 // If the LQ is the first/last histogram bin, then simply use 1410 // the midpoint of that bin. 1411 stats->robustLQ = 0.5 * (robustHistogram->bounds->data.F32[LQBinNum + 1] + 1412 robustHistogram->bounds->data.F32[LQBinNum]); 1413 } 1414 1415 if ((UQBinNum > 0) && (UQBinNum < (robustHistogram->nums->n - 1))) { 1416 x->data.F64[0] = (double)0.5 * 1417 (robustHistogram->bounds->data.F32[UQBinNum - 1] + 1418 robustHistogram->bounds->data.F32[UQBinNum]); 1419 x->data.F64[1] = (double)0.5 * 1420 (robustHistogram->bounds->data.F32[UQBinNum] + 1421 robustHistogram->bounds->data.F32[UQBinNum + 1]); 1422 x->data.F64[2] = (double)0.5 * 1423 (robustHistogram->bounds->data.F32[UQBinNum + 1] + 1424 robustHistogram->bounds->data.F32[UQBinNum + 2]); 1425 1426 y->data.F64[0] = cumulativeRobustSumsFullRange->data.F32[UQBinNum - 1]; 1427 y->data.F64[1] = cumulativeRobustSumsFullRange->data.F32[UQBinNum]; 1428 y->data.F64[2] = cumulativeRobustSumsFullRange->data.F32[UQBinNum + 1]; 1429 1430 if (!((y->data.F64[0] <= (3.0 * countFloat / 4.0)) && 1431 ((3.0 * countFloat / 4.0) <= y->data.F64[2]))) { 1432 psAbort(__func__, "p_psVectorRobustStats(3): midpoint not within y-range\n"); 1433 } 1434 1435 yErr->data.F64[0] = 1.0; 1436 yErr->data.F64[1] = 1.0; 1437 yErr->data.F64[2] = 1.0; 1438 1439 myPoly = psVectorFitPolynomial1D(myPoly, x, y, yErr); 1440 stats->robustUQ = p_ps1DPolyMedian(myPoly, 1441 x->data.F64[0], x->data.F64[2], 3.0 * countFloat / 4.0); 1442 } else { 1443 // If the UQ is the first/last histogram bin, then simply use 1444 // the midpoint of that bin. 1445 stats->robustUQ = 0.5 * (robustHistogram->bounds->data.F32[UQBinNum + 1] + 1446 robustHistogram->bounds->data.F32[UQBinNum]); 1447 } 1448 } 1323 countFloat = cumulativeRobustSums->data.F32[robustHistogramVector->n - 1]; 1324 1325 stats->robustLQ = fitQuadraticSearchForYThenReturnX(robustHistogram->bounds, 1326 cumulativeRobustSums, 1327 LQBinNum, 1328 countFloat/4.0); 1329 stats->robustUQ = fitQuadraticSearchForYThenReturnX(robustHistogram->bounds, 1330 cumulativeRobustSums, 1331 UQBinNum, 1332 3.0 * countFloat/4.0); 1333 } 1334 // XXX: I think sumNfit == sumN50 here. 1449 1335 stats->robustNfit = sumNfit; 1450 1336 stats->robustN50 = sumN50; 1451 1337 1452 psFree(x);1453 psFree(y);1454 psFree(yErr);1455 1338 psFree(tmpStats); 1456 1339 psFree(robustHistogram); 1457 psFree(myPoly); 1458 psFree(cumulativeRobustSumsFullRange); 1459 psFree(cumulativeRobustSumsDlRange); 1340 psFree(robustHistogramVector); 1341 psFree(cumulativeRobustSums); 1460 1342 } 1461 1343 … … 1468 1350 // I am commenting this code out, and replacing it with code which 1469 1351 // calculates the mean directly on the robustHistogram. 1470 //1471 // XXX: Replace this with the LaGrange interpolation stuff.1472 1352 1473 1353 domain = psImageAlloc(1, robustHistogramVector->n, PS_TYPE_F32); … … 1479 1359 max_pos = -1; 1480 1360 for (i=0;i<robustHistogramVector->n;i++) { 1481 domain->data.F32[i][0] = 0.5 * (robustHistogram->bounds->data.F32[i+1] + 1482 robustHistogram->bounds->data.F32[i]); 1361 domain->data.F32[i][0] = PS_BIN_MIDPOINT(robustHistogram, i);bounds->data.F32[modeBinNum + 1]); 1483 1362 data->data.F32[i] = (float) robustHistogramVector->data.F32[i]; 1484 1363 errors->data.F32[i] = 1.0; … … 1695 1574 psScalar tmpScalar; 1696 1575 tmpScalar.type.type = PS_TYPE_F32; 1576 psVector* inF32; 1577 int mustFreeTmp = 1; 1697 1578 1698 1579 // NOTE: Verify that this is the correct action. … … 1706 1587 1707 1588 if (out->nums->type.type != PS_TYPE_U32) { 1708 psAbort(__func__, "Only data type PS_TYPE_U32 for out put.nums member.");1589 psAbort(__func__, "Only data type PS_TYPE_U32 for out->nums member."); 1709 1590 } 1710 1591 // NOTE: Verify that this is the correct action. … … 1713 1594 } 1714 1595 1715 if (in->type.type != PS_TYPE_F32) {1716 psAbort(__func__, "Only data type PS_TYPE_F32 is currently supported (0x%x).", in->type.type);1717 }1718 1719 1596 if (mask != NULL) { 1720 1597 if (in->n != mask->n) { 1721 ps Abort(__func__, "Vector data and vector mask are of different sizes.");1598 psError(__func__, "Vector data and vector mask are of different sizes."); 1722 1599 } 1723 1600 if (mask->type.type != PS_TYPE_U8) { 1724 psAbort(__func__, "Vector mask must be type PS_TYPE_U8"); 1725 } 1601 psError(__func__, "Vector mask must be type PS_TYPE_U8"); 1602 } 1603 } 1604 1605 inF32 = p_psConvertToF32((psVector *) in); 1606 if (inF32 == NULL) { 1607 inF32 = (psVector *) in; 1608 mustFreeTmp = 0; 1726 1609 } 1727 1610 … … 1730 1613 1731 1614 numBins = out->nums->n; 1732 for (i = 0; i < in ->n; i++) {1615 for (i = 0; i < inF32->n; i++) { 1733 1616 // Check if this pixel is masked, and if so, skip it. 1734 1617 if ((mask == NULL) || ((mask != NULL) && (!(mask->data.U8[i] & maskVal)))) { 1735 1618 // Check if this pixel is below the minimum value, and if so 1736 1619 // count it, then skip it. 1737 if (in ->data.F32[i] < out->bounds->data.F32[0]) {1620 if (inF32->data.F32[i] < out->bounds->data.F32[0]) { 1738 1621 out->minNum++; 1739 1622 // Check if this pixel is above the maximum value, and if so 1740 1623 // count it, then skip it. 1741 } else if (in ->data.F32[i] > out->bounds->data.F32[numBins]) {1624 } else if (inF32->data.F32[i] > out->bounds->data.F32[numBins]) { 1742 1625 out->maxNum++; 1743 1626 } else { … … 1746 1629 if (out->uniform == true) { 1747 1630 binSize = out->bounds->data.F32[1] - out->bounds->data.F32[0]; 1748 binNum = (int)((in ->data.F32[i] - out->bounds->data.F32[0]) / binSize);1631 binNum = (int)((inF32->data.F32[i] - out->bounds->data.F32[0]) / binSize); 1749 1632 1750 1633 // NOTE: This next if-statement really shouldn't be necessary. … … 1755 1638 } 1756 1639 1757 (out->nums->data. S32[binNum])++;1640 (out->nums->data.U32[binNum])++; 1758 1641 1759 1642 // If this is a non-uniform histogram, determining the correct 1760 1643 // bin number requires a bit more work. 1761 1644 } else { 1762 tmpScalar.data.F32 = in->data.F32[i]; 1763 tmp = p_psVectorBinDisect(out->bounds, 1764 &tmpScalar); 1765 if (tmp == -1) { 1766 // XXX: Generate warning message 1645 tmpScalar.data.F32 = inF32->data.F32[i]; 1646 tmp = p_psVectorBinDisect(out->bounds, &tmpScalar); 1647 if (tmp < 0) { 1648 // XXX: Generate warning message 1767 1649 } else { 1768 (out->nums->data. S32[tmp])++;1650 (out->nums->data.U32[tmp])++; 1769 1651 } 1770 1652 } … … 1772 1654 } 1773 1655 } 1656 1657 if (mustFreeTmp == 1) { 1658 psFree(inF32); 1659 } 1774 1660 return (out); 1775 1661 } 1776 1662 1777 1663 /****************************************************************************** 1778 p_psConvertToF32(myVector, maskVector, maskVal, stats): this is the cheap 1779 way to support a variety of vector data types: we simply convert the input 1780 vector to F32 at the beginning, and write all of our functions in F32. If 1781 the vast majority of all vector stat operations are F32 (or any other single 1782 type), then this is probably the best way to go. Otherwise, when the 1783 algorithms stablize, we will then macro everything and put type support in 1784 the various stat functions. 1664 p_psConvertToF32(in): this is the cheap way to support a variety of vector 1665 data types: we simply convert the input vector to F32 at the beginning, and 1666 write all of our functions in F32. If the vast majority of all vector stat 1667 operations are F32 (or any other single type), then this is probably the 1668 best way to go. Otherwise, when the algorithms stablize, we will then macro 1669 everything and put type support in the various stat functions. 1785 1670 1786 1671 XXX: Should the default data type be F64? Since we are buying Athlons... 1787 1672 *****************************************************************************/ 1788 psVector* p_psConvertToF32(ps Stats* stats, psVector* in, psVector* mask, unsigned int maskVal)1673 psVector* p_psConvertToF32(psVector* in) 1789 1674 { 1790 1675 int i = 0; … … 1800 1685 for (i = 0; i < in->n; i++) { 1801 1686 tmp->data.F32[i] = (float)in->data.U16[i]; 1687 } 1688 } else if (in->type.type == PS_TYPE_U8) { 1689 tmp = psVectorAlloc(in->n, PS_TYPE_F32); 1690 for (i = 0; i < in->n; i++) { 1691 tmp->data.F32[i] = (float)in->data.U8[i]; 1802 1692 } 1803 1693 } else if (in->type.type == PS_TYPE_F64) { … … 1839 1729 int mustFreeTmp = 1; 1840 1730 1841 // NOTE: Verify that this is the correct action.1842 1731 if (in == NULL) { 1843 return (stats); 1844 } 1845 if (stats == NULL) { 1846 return (NULL); 1847 } 1848 1849 inF32 = p_psConvertToF32(stats, in, mask, maskVal); 1732 psError(__func__, "in is NULL\n"); 1733 return(stats); 1734 } 1735 PS_CHECK_NULL_PTR_RETURN_NULL(stats); 1736 1737 inF32 = p_psConvertToF32((psVector *) in); 1850 1738 if (inF32 == NULL) { 1851 1739 inF32 = in; 1852 1740 mustFreeTmp = 0; 1853 1741 } 1854 // XXX: Should we abort if (stats->min == stats->max)?1855 1742 if ((stats->options & PS_STAT_USE_RANGE) && (stats->min >= stats->max)) { 1856 psAbort(__func__, "psVectorStats() called with range: %f to %f\n", stats->min, stats->max); 1743 psError(__func__, "psVectorStats() called with range: %f to %f\n", stats->min, stats->max); 1744 return(stats); 1857 1745 } 1858 1746
Note:
See TracChangeset
for help on using the changeset viewer.
