- Timestamp:
- May 3, 2010, 8:50:52 AM (16 years ago)
- Location:
- branches/simtest_nebulous_branches
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
psLib/src/imageops/psImageConvolve.c (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/simtest_nebulous_branches
- Property svn:mergeinfo changed
-
branches/simtest_nebulous_branches/psLib/src/imageops/psImageConvolve.c
r24272 r27840 246 246 return kernel; 247 247 } 248 249 bool psKernelTruncate(psKernel *kernel, float frac) 250 { 251 PS_ASSERT_KERNEL_NON_NULL(kernel, false); 252 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(frac, 0.0, false); 253 PS_ASSERT_FLOAT_LESS_THAN(frac, 1.0, false); 254 255 if (frac == 0.0) { 256 // Nothing to do 257 return true; 258 } 259 260 int xMin = kernel->xMin, xMax = kernel->xMax, yMin = kernel->yMin, yMax = kernel->yMax; // Bounds 261 int maxSize = PS_MAX(PS_MAX(PS_MAX(-xMin, xMax), -yMin), yMax); // Maximum size 262 263 // Determine the threshold 264 // Summing absolute values because large negative deviations have power as well 265 double sumKernel = 0.0; // Sum of the kernel 266 for (int y = yMin; y <= yMax; y++) { 267 for (int x = xMin; x <= xMax; x++) { 268 sumKernel += fabsf(kernel->kernel[y][x]); 269 } 270 } 271 272 float threshold = sumKernel * (1.0 - frac); // Threshold for truncation 273 274 // Find truncation size 275 int truncate = 0; // Truncation radius 276 for (int radius = 1; truncate == 0 && radius < maxSize; radius++) { 277 int uMin = PS_MAX(-radius, xMin); 278 int uMax = PS_MIN(radius, xMax); 279 int vMin = PS_MAX(-radius, yMin); 280 int vMax = PS_MIN(radius, yMax); 281 int r2 = PS_SQR(radius); 282 double sum = 0.0; 283 for (int v = vMin; v <= vMax; v++) { 284 int v2 = PS_SQR(v); 285 for (int u = uMin; u <= uMax; u++) { 286 int u2 = PS_SQR(u); 287 if (u2 + v2 <= r2) { 288 sum += fabsf(kernel->kernel[v][u]); 289 } 290 } 291 } 292 if (sum > threshold) { 293 // This is the truncation radius 294 truncate = radius; 295 } 296 } 297 if (truncate == maxSize) { 298 // No truncation possible 299 return true; 300 } 301 302 // Truncate the kernel 303 { 304 int uMin = PS_MAX(-truncate, xMin); 305 int uMax = PS_MIN(truncate, xMax); 306 int vMin = PS_MAX(-truncate, yMin); 307 int vMax = PS_MIN(truncate, yMax); 308 int r2 = PS_SQR(truncate); 309 for (int v = vMin; v <= vMax; v++) { 310 int v2 = PS_SQR(v); 311 for (int u = uMin; u <= uMax; u++) { 312 int u2 = PS_SQR(u); 313 if (u2 + v2 > r2) { 314 kernel->kernel[v][u] = 0.0; 315 } 316 } 317 } 318 } 319 kernel->xMin = PS_MAX(-truncate, kernel->xMin); 320 kernel->xMax = PS_MIN(truncate, kernel->xMax); 321 kernel->yMin = PS_MAX(-truncate, kernel->yMin); 322 kernel->yMax = PS_MIN(truncate, kernel->yMax); 323 324 return true; 325 } 326 327 248 328 249 329 psImage *psImageConvolveDirect(psImage *out, const psImage *in, const psKernel *kernel) … … 678 758 } 679 759 760 static bool imageSmoothMaskPixels(psVector *out, const psImage *image, const psImage *mask, 761 psImageMaskType maskVal, const psVector *x, const psVector *y, 762 const psVector *gaussNorm, float minGauss, int size, int start, int stop) 763 { 764 const psF32 *gauss = &gaussNorm->data.F32[size]; // Gaussian convolution kernel 765 int numCols = image->numCols, numRows = image->numRows; // Size of image 766 int xLast = numCols - 1, yLast = numRows - 1; // Last index 767 for (int i = start; i < stop; i++) { 768 int xPix = x->data.S32[i], yPix = y->data.S32[i]; // Pixel coordinates for smoothing 769 770 int yMin = PS_MAX(yPix - size, 0); 771 int yMax = PS_MIN(yPix + size, yLast); 772 int xMin = PS_MAX(xPix - size, 0); 773 int xMax = PS_MIN(xPix + size, xLast); 774 775 const float *yGauss = &gauss[yMin - yPix]; 776 777 double ySumIG = 0.0, ySumG = 0.0; 778 for (int v = yMin; v <= yMax; v++, yGauss++) { 779 const float *xGauss = &gauss[xMin - xPix]; 780 double xSumIG = 0.0, xSumG = 0.0; 781 const psImageMaskType *maskData = &mask->data.PS_TYPE_IMAGE_MASK_DATA[v][xMin]; 782 const psF32 *imageData = &image->data.F32[v][xMin]; 783 for (int u = xMin; u <= xMax; u++, xGauss++, imageData++, maskData++) { 784 if (*maskData & maskVal) { 785 continue; 786 } 787 xSumIG += *imageData * *xGauss; 788 xSumG += *xGauss; 789 } 790 if (xSumG > minGauss) { 791 ySumIG += xSumIG * *yGauss; 792 ySumG += xSumG * *yGauss; 793 } 794 } 795 796 out->data.F32[i] = ySumG > minGauss ? ySumIG / ySumG : NAN; 797 } 798 799 return true; 800 } 801 802 static bool psImageSmoothMaskPixelsThread(psThreadJob *job) 803 { 804 PS_ASSERT_THREAD_JOB_NON_NULL(job, false); 805 psAssert(job->args, "programming error: no job arguments"); 806 psAssert(job->args->n == 11, "programming error: wrong number of job arguments"); 807 808 psVector *out = job->args->data[0]; // Output vector 809 const psImage *image = job->args->data[1]; // Input image 810 const psImage *mask = job->args->data[2]; // Input mask 811 psImageMaskType maskVal = PS_SCALAR_VALUE(job->args->data[3], PS_TYPE_IMAGE_MASK_DATA); 812 const psVector *x = job->args->data[4]; 813 const psVector *y = job->args->data[5]; 814 const psVector *gaussNorm = job->args->data[6]; 815 float minGauss = PS_SCALAR_VALUE(job->args->data[7], F32); 816 int size = PS_SCALAR_VALUE(job->args->data[8], S32); 817 int start = PS_SCALAR_VALUE(job->args->data[9], S32); 818 int stop = PS_SCALAR_VALUE(job->args->data[10], S32); 819 return imageSmoothMaskPixels(out, image, mask, maskVal, x, y, gaussNorm, 820 minGauss, size, start, stop); 821 } 822 823 824 psVector *psImageSmoothMaskPixels(const psImage *image, const psImage *mask, psImageMaskType maskVal, 825 const psVector *x, const psVector *y, 826 float sigma, float numSigma, float minGauss) 827 { 828 PS_ASSERT_IMAGE_NON_NULL(image, NULL); 829 PS_ASSERT_IMAGE_NON_NULL(mask, NULL); 830 PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_IMAGE_MASK, NULL); 831 PS_ASSERT_IMAGES_SIZE_EQUAL(image, mask, NULL); 832 PS_ASSERT_VECTOR_NON_NULL(x, NULL); 833 PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_S32, NULL); 834 PS_ASSERT_VECTOR_NON_NULL(y, NULL); 835 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_S32, NULL); 836 PS_ASSERT_VECTORS_SIZE_EQUAL(x, y, NULL); 837 838 int size = sigma * numSigma + 0.5; // Half-size of kernel 839 840 int num = x->n; // Number of pixels to smooth 841 psVector *out = psVectorAlloc(num, PS_TYPE_F32); // Output results 842 843 // Generate normalized gaussian 844 IMAGE_SMOOTH_GAUSS(gaussNorm, size, sigma, F32); 845 846 // Columns 847 if (threaded) { 848 int numThreads = psThreadPoolSize(); // Number of threads 849 int delta = (numThreads) ? num / numThreads + 1 : num; // Block of cols to do at once 850 for (int start = 0; start < num; start += delta) { 851 int stop = PS_MIN(start + delta, num); // End of block 852 853 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTHMASK_PIXELS"); 854 psArrayAdd(job->args, 1, out); 855 psArrayAdd(job->args, 1, (psImage*)image); 856 psArrayAdd(job->args, 1, (psImage*)mask); 857 PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK); 858 psArrayAdd(job->args, 1, (psVector*)x); 859 psArrayAdd(job->args, 1, (psVector*)y); 860 psArrayAdd(job->args, 1, gaussNorm); 861 PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32); 862 PS_ARRAY_ADD_SCALAR(job->args, size, PS_TYPE_S32); 863 PS_ARRAY_ADD_SCALAR(job->args, start, PS_TYPE_S32); 864 PS_ARRAY_ADD_SCALAR(job->args, stop, PS_TYPE_S32); 865 if (!psThreadJobAddPending(job)) { 866 psFree(job); 867 psFree(gaussNorm); 868 psFree(out); 869 return NULL; 870 } 871 psFree(job); 872 } 873 } else if (!imageSmoothMaskPixels(out, image, mask, maskVal, x, y, 874 gaussNorm, minGauss, size, 0, num)) { 875 psError(PS_ERR_UNKNOWN, false, "Unable to smooth pixels."); 876 psFree(gaussNorm); 877 psFree(out); 878 return NULL; 879 } 880 881 if (threaded && !psThreadPoolWait(true)) { 882 psError(PS_ERR_UNKNOWN, false, "Error waiting for threads."); 883 psFree(gaussNorm); 884 psFree(out); 885 return NULL; 886 } 887 888 psFree(gaussNorm); 889 return out; 890 } 891 892 680 893 // Smooth an image with masked pixels 681 894 // The calculation and calcMask images are *deliberately* backwards (row,col instead of col,row or … … 1325 1538 if (threaded) { 1326 1539 int numThreads = psThreadPoolSize(); // Number of threads 1327 int deltaRows = (numThreads) ? numRows / numThreads : numRows; // Block of rows to do at once1540 int deltaRows = (numThreads) ? numRows / numThreads + 1 : numRows; // Block of rows to do at once 1328 1541 for (int start = 0; start < numRows; start += deltaRows) { 1329 int stop = PS_MIN (start + deltaRows, numRows); // end of row block1542 int stop = PS_MIN(start + deltaRows, numRows); // end of row block 1330 1543 1331 1544 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_CONVOLVE_MASK"); … … 1363 1576 if (threaded) { 1364 1577 int numThreads = psThreadPoolSize(); // Number of threads 1365 int deltaCols = (numThreads) ? numCols / numThreads : numCols; // Block of cols to do at once1578 int deltaCols = (numThreads) ? numCols / numThreads + 1 : numCols; // Block of cols to do at once 1366 1579 for (int start = 0; start < numCols; start += deltaCols) { 1367 int stop = PS_MIN (start + deltaCols, numCols); // end of col block1580 int stop = PS_MIN(start + deltaCols, numCols); // end of col block 1368 1581 1369 1582 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_CONVOLVE_MASK"); … … 1486 1699 psFree(task); 1487 1700 } 1701 { 1702 psThreadTask *task = psThreadTaskAlloc("PSLIB_IMAGE_SMOOTHMASK_PIXELS", 9); 1703 task->function = &psImageSmoothMaskPixelsThread; 1704 psThreadTaskAdd(task); 1705 psFree(task); 1706 } 1488 1707 } else if (!set && threaded) { 1489 1708 psThreadTaskRemove("PSLIB_IMAGE_CONVOLVE_MASK");
Note:
See TracChangeset
for help on using the changeset viewer.
