Changeset 26892 for trunk/psLib/src/imageops/psImageCovariance.c
- Timestamp:
- Feb 10, 2010, 7:27:29 PM (16 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/imageops/psImageCovariance.c (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/imageops/psImageCovariance.c
r25994 r26892 14 14 #include "psTrace.h" 15 15 #include "psBinaryOp.h" 16 #include "psScalar.h" 17 #include "psThread.h" 16 18 17 19 #include "psImageCovariance.h" 20 21 static bool threaded = false; // Run threaded? 22 18 23 19 24 psKernel *psImageCovarianceNone(void) … … 24 29 } 25 30 26 27 psKernel *psImageCovarianceCalculate(const psKernel *kernel, const psKernel *covariance) 28 { 29 PS_ASSERT_KERNEL_NON_NULL(kernel, NULL); 30 31 // See http://en.wikipedia.org/wiki/Error_propagation 32 // 33 // If 34 // f_k = sum_i A_ik x_i 35 // is a set of functions, then the covariance matrix for f is given by: 36 // M^f_ij = sum_k sum_l A_ik M^x_kl A_lj 37 // where M^x is the covariance matrix for x. 38 // Note that the errors in f are correlated (covariance) even if the errors in x are not. 39 40 psKernel *covar; // Covariance matrix to use 41 if (covariance) { 42 covar = psMemIncrRefCounter((psKernel*)covariance); // Casting away const 43 } else { 44 covar = psImageCovarianceNone(); 45 } 46 47 // Check for non-finite elements 48 for (int y = kernel->yMin; y <= kernel->yMax; y++) { 49 for (int x = kernel->xMin; x <= kernel->xMax; x++) { 50 if (!isfinite(kernel->kernel[y][x])) { 51 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 52 "Non-finite covariance matrix element in kernel at %d,%d", x, y); 53 psFree(covar); 54 return NULL; 55 } 56 } 57 } 58 for (int y = covar->yMin; y <= covar->yMax; y++) { 59 for (int x = covar->xMin; x <= covar->xMax; x++) { 60 if (!isfinite(covar->kernel[y][x])) { 61 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 62 "Non-finite covariance matrix element in covariance matrix at %d,%d", x, y); 63 psFree(covar); 64 return NULL; 65 } 66 } 67 } 68 69 // The above (double) sum for the covariance matrix means that, for each point in the output covariance 70 // matrix, we need to work out all combinations of getting to the central point via a kernel, input 71 // covariance matrix and another kernel. This means that the resultant covariance matrix has twice the 72 // size of the kernel plus the size of the input covariance matrix. 73 int xMin = kernel->xMin - kernel->xMax + covar->xMin, xMax = kernel->xMax - kernel->xMin + covar->xMax; 74 int yMin = kernel->yMin - kernel->yMax + covar->yMin, yMax = kernel->yMax - kernel->yMin + covar->yMax; 75 psKernel *out = psKernelAlloc(xMin, xMax, yMin, yMax); // Covariance matrix for output 31 /// Calculation of covariance matrix element when convolving 32 static float imageCovarianceCalculate(const psKernel *covar, // Original covariance matrix 33 const psKernel *kernel, // Convolution kernel 34 int x, int y // Coordinates in output covariance matrix 35 ) 36 { 37 psAssert(covar, "Require covariance matrix"); 38 psAssert(kernel, "Require kernel"); 76 39 77 40 // Need to go: … … 89 52 // from the source coordinate), we take the smallest possible (because everything else is zero outside). 90 53 91 double total = 0.0; // Total covariance 54 // Range for v 55 int vMin = PS_MAX(kernel->yMin + covar->yMin, y + kernel->yMin); 56 int vMax = PS_MIN(kernel->yMax + covar->yMax, y + kernel->yMax); 57 // Range for u 58 int uMin = PS_MAX(kernel->xMin + covar->xMin, x + kernel->xMin); 59 int uMax = PS_MIN(kernel->xMax + covar->xMax, x + kernel->xMax); 60 61 double sum = 0.0; // Sum for value of covariance matrix at (x,y) 62 for (int v = vMin; v <= vMax; v++) { 63 // Range for q 64 int qMin = PS_MAX(v + covar->yMin, kernel->yMin); 65 int qMax = PS_MIN(v + covar->yMax, kernel->yMax); 66 for (int u = uMin; u <= uMax; u++) { 67 // Range for p 68 int pMin = PS_MAX(u + covar->xMin, kernel->xMin); 69 int pMax = PS_MIN(u + covar->xMax, kernel->xMax); 70 71 double xyuvValue = kernel->kernel[v-y][u-x]; // Value for (x,y) --> (u,v) 72 73 double uvpqValue = 0.0; // Value for (u,v) --> (p,q) --> (0,0) 74 for (int q = qMin; q <= qMax; q++) { 75 for (int p = pMin; p <= pMax; p++) { 76 uvpqValue += (double)covar->kernel[q-v][p-u] * (double)kernel->kernel[q][p]; 77 } 78 } 79 sum += xyuvValue * uvpqValue; 80 } 81 } 82 83 return sum; 84 } 85 86 /// Thread entry point for calculation of covariance matrix element when convolving 87 static bool imageCovarianceCalculateThread(psThreadJob *job) 88 { 89 PS_ASSERT_THREAD_JOB_NON_NULL(job, false); 90 psAssert(job->args, "No job arguments"); 91 psAssert(job->args->n == 5, "Wrong number of job arguments: %ld", job->args->n); 92 93 psKernel *out = job->args->data[0]; // Output covariance matrix 94 const psKernel *covar = job->args->data[1]; // Input covariance matrix 95 const psKernel *kernel = job->args->data[2]; // Convolution kernel 96 int x = PS_SCALAR_VALUE(job->args->data[3], S32); // x coordinate in output covariance matrix 97 int y = PS_SCALAR_VALUE(job->args->data[4], S32); // y coordinate in output covariance matrix 98 99 out->kernel[y][x] = imageCovarianceCalculate(covar, kernel, x, y); 100 101 return true; 102 } 103 104 105 106 psKernel *psImageCovarianceCalculate(const psKernel *kernel, const psKernel *covariance) 107 { 108 PS_ASSERT_KERNEL_NON_NULL(kernel, NULL); 109 110 // See http://en.wikipedia.org/wiki/Error_propagation 111 // 112 // If 113 // f_k = sum_i A_ik x_i 114 // is a set of functions, then the covariance matrix for f is given by: 115 // M^f_ij = sum_k sum_l A_ik M^x_kl A_lj 116 // where M^x is the covariance matrix for x. 117 // Note that the errors in f are correlated (covariance) even if the errors in x are not. 118 119 psKernel *covar; // Covariance matrix to use 120 if (covariance) { 121 covar = psMemIncrRefCounter((psKernel*)covariance); // Casting away const 122 } else { 123 covar = psImageCovarianceNone(); 124 } 125 126 // Check for non-finite elements 127 for (int y = kernel->yMin; y <= kernel->yMax; y++) { 128 for (int x = kernel->xMin; x <= kernel->xMax; x++) { 129 if (!isfinite(kernel->kernel[y][x])) { 130 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 131 "Non-finite covariance matrix element in kernel at %d,%d", x, y); 132 psFree(covar); 133 return NULL; 134 } 135 } 136 } 137 for (int y = covar->yMin; y <= covar->yMax; y++) { 138 for (int x = covar->xMin; x <= covar->xMax; x++) { 139 if (!isfinite(covar->kernel[y][x])) { 140 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 141 "Non-finite covariance matrix element in covariance matrix at %d,%d", x, y); 142 psFree(covar); 143 return NULL; 144 } 145 } 146 } 147 148 // The above (double) sum for the covariance matrix means that, for each point in the output covariance 149 // matrix, we need to work out all combinations of getting to the central point via a kernel, input 150 // covariance matrix and another kernel. This means that the resultant covariance matrix has twice the 151 // size of the kernel plus the size of the input covariance matrix. 152 int xMin = kernel->xMin - kernel->xMax + covar->xMin, xMax = kernel->xMax - kernel->xMin + covar->xMax; 153 int yMin = kernel->yMin - kernel->yMax + covar->yMin, yMax = kernel->yMax - kernel->yMin + covar->yMax; 154 psKernel *out = psKernelAlloc(xMin, xMax, yMin, yMax); // Covariance matrix for output 155 92 156 for (int y = yMin; y <= yMax; y++) { 93 // Range for v94 int vMin = PS_MAX(kernel->yMin + covar->yMin, y + kernel->yMin);95 int vMax = PS_MIN(kernel->yMax + covar->yMax, y + kernel->yMax);96 157 for (int x = xMin; x <= xMax; x++) { 97 // Range for u 98 int uMin = PS_MAX(kernel->xMin + covar->xMin, x + kernel->xMin); 99 int uMax = PS_MIN(kernel->xMax + covar->xMax, x + kernel->xMax); 100 101 double sum = 0.0; // Sum for value of covariance matrix at (x,y) 102 for (int v = vMin; v <= vMax; v++) { 103 // Range for q 104 int qMin = PS_MAX(v + covar->yMin, kernel->yMin); 105 int qMax = PS_MIN(v + covar->yMax, kernel->yMax); 106 for (int u = uMin; u <= uMax; u++) { 107 // Range for p 108 int pMin = PS_MAX(u + covar->xMin, kernel->xMin); 109 int pMax = PS_MIN(u + covar->xMax, kernel->xMax); 110 111 double xyuvValue = kernel->kernel[v-y][u-x]; // Value for (x,y) --> (u,v) 112 113 double uvpqValue = 0.0; // Value for (u,v) --> (p,q) --> (0,0) 114 for (int q = qMin; q <= qMax; q++) { 115 for (int p = pMin; p <= pMax; p++) { 116 uvpqValue += (double)covar->kernel[q-v][p-u] * (double)kernel->kernel[q][p]; 117 } 118 } 119 sum += xyuvValue * uvpqValue; 158 if (threaded) { 159 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_COVARIANCE_CALCULATE"); 160 psArrayAdd(job->args, 1, out); 161 psArrayAdd(job->args, 1, covar); 162 psArrayAdd(job->args, 1, (psKernel*)kernel); // Casting away const 163 PS_ARRAY_ADD_SCALAR(job->args, x, PS_TYPE_S32); 164 PS_ARRAY_ADD_SCALAR(job->args, y, PS_TYPE_S32); 165 if (!psThreadJobAddPending(job)) { 166 psFree(covar); 167 return NULL; 120 168 } 121 } 122 out->kernel[y][x] = sum; 123 total += sum; 124 } 125 } 126 psTrace("psLib.imageops", 3, "Total covariance: %lf ; Central variance: %f\n", total, out->kernel[0][0]); 127 169 psFree(job); 170 } else { 171 out->kernel[y][x] = imageCovarianceCalculate(covar, kernel, x, y); 172 } 173 } 174 } 128 175 psFree(covar); 176 177 if (threaded && !psThreadPoolWait(true)) { 178 psError(PS_ERR_UNKNOWN, false, "Error waiting for threads."); 179 return false; 180 } 181 129 182 return out; 130 183 } 184 185 float psImageCovarianceCalculateFactor(const psKernel *kernel, const psKernel *covariance) 186 { 187 psKernel *covar; // Covariance matrix to use 188 if (covariance) { 189 covar = psMemIncrRefCounter((psKernel*)covariance); // Casting away const 190 } else { 191 covar = psImageCovarianceNone(); 192 } 193 194 // Check for non-finite elements 195 for (int y = kernel->yMin; y <= kernel->yMax; y++) { 196 for (int x = kernel->xMin; x <= kernel->xMax; x++) { 197 if (!isfinite(kernel->kernel[y][x])) { 198 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 199 "Non-finite covariance matrix element in kernel at %d,%d", x, y); 200 psFree(covar); 201 return NAN; 202 } 203 } 204 } 205 for (int y = covar->yMin; y <= covar->yMax; y++) { 206 for (int x = covar->xMin; x <= covar->xMax; x++) { 207 if (!isfinite(covar->kernel[y][x])) { 208 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 209 "Non-finite covariance matrix element in covariance matrix at %d,%d", x, y); 210 psFree(covar); 211 return NAN; 212 } 213 } 214 } 215 216 float factor = imageCovarianceCalculate(covar, kernel, 0, 0); // Covariance factor 217 psFree(covar); 218 return factor; 219 } 220 221 // Calculation of covariance matrix element when binning 222 static float imageCovarianceBin(const psKernel *covar, // Original covariance matrix 223 int bin, // Binning factor 224 float binVal, // Convolution kernel value for binning 225 int x, int y // Coordinates in output covariance matrix 226 ) 227 { 228 psAssert(covar, "Require covariance matrix"); 229 psAssert(bin > 0 && binVal > 0, "Require binning: %d %f", bin, binVal); 230 231 int binMin = -(bin - 1) / 2, binMax = bin / 2; // Range of "kernel" 232 233 // Range for v 234 int vMin = PS_MAX(binMin + covar->yMin, bin * y + binMin); 235 int vMax = PS_MIN(binMax + covar->yMax, bin * y + binMax); 236 // Range for u 237 int uMin = PS_MAX(binMin + covar->xMin, bin * x + binMin); 238 int uMax = PS_MIN(binMax + covar->xMax, bin * x + binMax); 239 240 double sum = 0.0; // Sum for value of covariance matrix at (x,y) 241 for (int v = vMin; v <= vMax; v++) { 242 // Range for q 243 int qMin = PS_MAX(v + covar->yMin, binMin); 244 int qMax = PS_MIN(v + covar->yMax, binMax); 245 for (int u = uMin; u <= uMax; u++) { 246 // Range for p 247 int pMin = PS_MAX(u + covar->xMin, binMin); 248 int pMax = PS_MIN(u + covar->xMax, binMax); 249 250 double xyuvValue = binVal; // Value for (x,y) --> (u,v) 251 252 double uvpqValue = 0.0; // Value for (u,v) --> (p,q) --> (0,0) 253 for (int q = qMin; q <= qMax; q++) { 254 for (int p = pMin; p <= pMax; p++) { 255 uvpqValue += (double)covar->kernel[q-v][p-u] * (double)binVal; 256 } 257 } 258 sum += xyuvValue * uvpqValue; 259 } 260 } 261 262 return sum; 263 } 264 265 /// Thread entry point for calculation of covariance matrix element when binning 266 static bool imageCovarianceBinThread(psThreadJob *job) 267 { 268 PS_ASSERT_THREAD_JOB_NON_NULL(job, false); 269 psAssert(job->args, "No job arguments"); 270 psAssert(job->args->n == 6, "Wrong number of job arguments: %ld", job->args->n); 271 272 psKernel *out = job->args->data[0]; // Output covariance matrix 273 const psKernel *covar = job->args->data[1]; // Input covariance matrix 274 int bin = PS_SCALAR_VALUE(job->args->data[2], S32); // Binning factor 275 float binVal = PS_SCALAR_VALUE(job->args->data[3], F32); // Convolution kernel value for binning 276 int x = PS_SCALAR_VALUE(job->args->data[4], S32); // x coordinate in output covariance matrix 277 int y = PS_SCALAR_VALUE(job->args->data[5], S32); // y coordinate in output covariance matrix 278 279 out->kernel[y][x] = imageCovarianceBin(covar, bin, binVal, x, y); 280 281 return true; 282 } 283 131 284 132 285 psKernel *psImageCovarianceBin(int bin, const psKernel *covariance, bool average) … … 165 318 psKernel *out = psKernelAlloc(xMin, xMax, yMin, yMax); // Covariance matrix for output 166 319 167 double total = 0.0; // Total covariance168 320 for (int y = yMin; y <= yMax; y++) { 169 // Range for v170 int vMin = PS_MAX(binMin + covar->yMin, bin * y + binMin);171 int vMax = PS_MIN(binMax + covar->yMax, bin * y + binMax);172 321 for (int x = xMin; x <= xMax; x++) { 173 // Range for u 174 int uMin = PS_MAX(binMin + covar->xMin, bin * x + binMin); 175 int uMax = PS_MIN(binMax + covar->xMax, bin * x + binMax); 176 177 double sum = 0.0; // Sum for value of covariance matrix at (x,y) 178 for (int v = vMin; v <= vMax; v++) { 179 // Range for q 180 int qMin = PS_MAX(v + covar->yMin, binMin); 181 int qMax = PS_MIN(v + covar->yMax, binMax); 182 for (int u = uMin; u <= uMax; u++) { 183 // Range for p 184 int pMin = PS_MAX(u + covar->xMin, binMin); 185 int pMax = PS_MIN(u + covar->xMax, binMax); 186 187 double xyuvValue = binVal; // Value for (x,y) --> (u,v) 188 189 double uvpqValue = 0.0; // Value for (u,v) --> (p,q) --> (0,0) 190 for (int q = qMin; q <= qMax; q++) { 191 for (int p = pMin; p <= pMax; p++) { 192 uvpqValue += (double)covar->kernel[q-v][p-u] * (double)binVal; 193 } 194 } 195 sum += xyuvValue * uvpqValue; 322 if (threaded) { 323 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_COVARIANCE_BIN"); 324 psArrayAdd(job->args, 1, out); 325 psArrayAdd(job->args, 1, covar); 326 PS_ARRAY_ADD_SCALAR(job->args, bin, PS_TYPE_S32); 327 PS_ARRAY_ADD_SCALAR(job->args, binVal, PS_TYPE_F32); 328 PS_ARRAY_ADD_SCALAR(job->args, x, PS_TYPE_S32); 329 PS_ARRAY_ADD_SCALAR(job->args, y, PS_TYPE_S32); 330 if (!psThreadJobAddPending(job)) { 331 psFree(covar); 332 return NULL; 196 333 } 197 } 198 out->kernel[y][x] = sum; 199 total += sum; 200 } 201 } 202 psTrace("psLib.imageops", 3, "Total covariance: %lf ; Central variance: %f\n", total, out->kernel[0][0]); 203 334 psFree(job); 335 } else { 336 out->kernel[y][x] = imageCovarianceBin(covar, bin, binVal, x, y); 337 } 338 } 339 } 204 340 psFree(covar); 205 341 342 if (threaded && !psThreadPoolWait(true)) { 343 psError(PS_ERR_UNKNOWN, false, "Error waiting for threads."); 344 return false; 345 } 346 206 347 return out; 207 348 } … … 219 360 220 361 for (int y = covar->yMin; y <= covar->yMax; y++) { 221 if (y < -radius) continue;222 if (y > +radius) continue;223 for (int x = covar->xMin; x <= covar->xMax; x++) {224 if (x < -radius) continue;225 if (x > +radius) continue;226 227 if (hypot(x, y) > radius) continue;228 229 psAssert (isfinite(covar->kernel[y][x]), "invalid NAN in covariance matrix");230 Sum += covar->kernel[y][x];231 }362 if (y < -radius) continue; 363 if (y > +radius) continue; 364 for (int x = covar->xMin; x <= covar->xMax; x++) { 365 if (x < -radius) continue; 366 if (x > +radius) continue; 367 368 if (hypot(x, y) > radius) continue; 369 370 psAssert (isfinite(covar->kernel[y][x]), "invalid NAN in covariance matrix"); 371 Sum += covar->kernel[y][x]; 372 } 232 373 } 233 374 … … 428 569 return true; 429 570 } 571 572 573 bool psImageCovarianceSetThreads(bool set) 574 { 575 bool old = threaded; // Old value 576 if (set && !threaded) { 577 { 578 psThreadTask *task = psThreadTaskAlloc("PSLIB_IMAGE_COVARIANCE_CALCULATE", 5); 579 task->function = &imageCovarianceCalculateThread; 580 psThreadTaskAdd(task); 581 psFree(task); 582 } 583 { 584 psThreadTask *task = psThreadTaskAlloc("PSLIB_IMAGE_COVARIANCE_BIN", 6); 585 task->function = &imageCovarianceBinThread; 586 psThreadTaskAdd(task); 587 psFree(task); 588 } 589 } else if (!set && threaded) { 590 psThreadTaskRemove("PSLIB_IMAGE_COVARIANCE_CALCULATE"); 591 psThreadTaskRemove("PSLIB_IMAGE_COVARIANCE_BIN"); 592 } 593 threaded = set; 594 return old; 595 } 596 597 bool psImageCovarianceGetThreads(void) 598 { 599 return threaded; 600 }
Note:
See TracChangeset
for help on using the changeset viewer.
