- Timestamp:
- Mar 5, 2012, 5:19:48 PM (14 years ago)
- Location:
- branches/meh_branches/ppstack_test
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
psLib/src/imageops/psImageConvolve.c (modified) (23 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/meh_branches/ppstack_test
- Property svn:mergeinfo changed
-
branches/meh_branches/ppstack_test/psLib/src/imageops/psImageConvolve.c
r30595 r33415 569 569 // Generate normalised Gaussian vector 570 570 #define IMAGE_SMOOTH_GAUSS(TARGET, SIZE, SIGMA, TYPE) \ 571 psVector *TARGET = psVectorAlloc(2 * SIZE + 1, PS_TYPE_##TYPE); /* Gaussian */ \571 TARGET = psVectorAlloc(2 * SIZE + 1, PS_TYPE_##TYPE); /* Gaussian */ \ 572 572 double sum = 0.0; /* Sum of Gaussian, for normalisation */ \ 573 573 double factor = -0.5/PS_SQR(SIGMA); /* Multiplier for exponential */ \ … … 587 587 psKernel *kernel = psKernelAlloc(-size, size, -size, size); // Kernel to return 588 588 589 psVector *gaussNorm = NULL; 589 590 IMAGE_SMOOTH_GAUSS(gaussNorm, size, sigma, F32); 590 591 psF32 *gauss = &gaussNorm->data.F32[size]; // Convenient kernel-like indexing for Gaussian … … 602 603 bool psImageSmooth(psImage *image, double sigma, double Nsigma) 603 604 { 604 PS_ASSERT_IMAGE_NON_NULL(image, NULL);605 PS_ASSERT_IMAGE_NON_NULL(image, false); 605 606 606 607 // relevant terms … … 612 613 case PS_TYPE_##TYPE: { \ 613 614 /* generate normalized gaussian */ \ 615 psVector *gaussnorm = NULL; \ 614 616 IMAGE_SMOOTH_GAUSS(gaussnorm, Nrange, sigma, TYPE) \ 615 617 ps##TYPE *gauss = &gaussnorm->data.TYPE[Nrange]; \ … … 622 624 ps##TYPE *vo = calculation->data.TYPE; \ 623 625 int xMax = PS_MIN(Nrange, Nx); \ 624 int convRange = PS_MIN(Nrange + 1, Nx); \625 626 /* Smooth first Nrange pixels, with renorm */ \ 626 627 for (int i = 0; i < xMax; i++, vi++, vo++) { \ 628 int convRange = PS_MIN(Nrange + 1, Nx - i); \ 627 629 ps##TYPE *vr = vi - i; \ 628 630 ps##TYPE *vg = gauss - i; \ … … 648 650 } \ 649 651 /* Smooth last Nrange pixels, with renorm */ \ 650 /* XXX does this miss the last column? */ \ 651 for (int i = Nx - Nrange; i < Nx; i++, vi++, vo++) { \ 652 /* if Nx < 2*Nrange, this pass starts at i == Nrange */ \ 653 int xMin = PS_MAX(Nx - Nrange, Nrange); \ 654 for (int i = xMin; i < Nx; i++, vi++, vo++) { \ 652 655 ps##TYPE *vr = vi - Nrange; \ 653 656 ps##TYPE *vg = gauss - Nrange; \ … … 670 673 /* Smooth the first Nrange pixels, with renorm */ \ 671 674 int yMax = PS_MIN(Nrange, Ny); \ 672 int convRange = PS_MIN(Nrange + 1, Ny); \673 675 for (int j = 0; j < yMax; j++) { \ 676 int convRange = PS_MIN(Nrange + 1, Ny - j); \ 674 677 psVector *calculation = psVectorAlloc(Nx, PS_TYPE_##TYPE); \ 675 678 /* Zero the output row */ \ … … 715 718 calculation = save; \ 716 719 } \ 717 /* Smooth last Nrange pixels, with renorm */ \ 718 for (int j = Ny - Nrange; j < Ny; j++) { \ 720 /* Smooth last Nrange pixels, with renorm */ \ 721 /* if Ny < 2*Nrange, this pass starts at j == Nrange */ \ 722 int yMin = PS_MAX(Ny - Nrange, Nrange); \ 723 for (int j = yMin; j < Ny; j++) { \ 719 724 /* save the Nrange-offset output row, then zero */ \ 720 725 memset(calculation->data.TYPE, 0, Nx*sizeof(ps##TYPE)); \ … … 765 770 } 766 771 772 void psImageSmooth_PreAlloc_DataFree (psImageSmooth_PreAlloc_Data *smdata) { 773 psFree (smdata->resultX); 774 psFree (smdata->resultY); 775 psFree (smdata->kernel); 776 } 777 778 psImageSmooth_PreAlloc_Data *psImageSmooth_PreAlloc_DataAlloc (psImage *image, double sigma, double Nsigma) { 779 780 psImageSmooth_PreAlloc_Data *smdata = psAlloc(sizeof(psImageSmooth_PreAlloc_Data)); 781 psMemSetDeallocator(smdata, (psFreeFunc) psImageSmooth_PreAlloc_DataFree); 782 783 if (!image) { 784 // relevant terms 785 smdata->Nrange = sigma*Nsigma + 0.5; // Number of pixels either side for convolution kernel 786 smdata->Nx = 0; 787 smdata->Ny = 0; 788 smdata->kernel = NULL; 789 smdata->resultX = NULL; 790 smdata->resultY = NULL; 791 return smdata; 792 } 793 794 // relevant terms 795 smdata->Nrange = sigma*Nsigma + 0.5; // Number of pixels either side for convolution kernel 796 smdata->Nx = image->numCols; // Number of columns 797 smdata->Ny = image->numRows; // Number of rows 798 799 IMAGE_SMOOTH_GAUSS(smdata->kernel, smdata->Nrange, sigma, F32); 800 801 // use a temp running buffer for X and Y directions. 802 smdata->resultX = psAlloc(smdata->Nx * sizeof(psF32)); 803 memset (smdata->resultX, 0, smdata->Nx*sizeof(psF32)); 804 805 smdata->resultY = psAlloc(smdata->Ny * sizeof(psF32)); 806 memset (smdata->resultY, 0, smdata->Ny*sizeof(psF32)); 807 808 return smdata; 809 } 810 811 // we can use the same DATA structure on multiple images of the same size 812 bool psImageSmooth_PreAlloc_F32(psImage *image, psImageSmooth_PreAlloc_Data *smdata) 813 { 814 PS_ASSERT_IMAGE_NON_NULL(image, false); 815 // assert on data type 816 817 // relevant terms 818 int Nrange = smdata->Nrange; // Number of pixels either side for convolution kernel 819 int Nx = smdata->Nx; // Number of columns 820 int Ny = smdata->Ny; // Number of rows 821 822 psF32 *gauss = &smdata->kernel->data.F32[Nrange]; 823 psF32 *resultX = smdata->resultX; 824 psF32 *resultY = smdata->resultY; 825 826 /* Smooth in X direction */ 827 { 828 for (int j = 0; j < Ny; j++) { 829 psF32 *vi = image->data.F32[j]; 830 int xMax = PS_MIN(Nrange, Nx); 831 /* Smooth first Nrange pixels, with renorm */ 832 for (int i = 0; i < xMax; i++, vi++) { 833 int convRange = PS_MIN(Nrange + 1, Nx - i); 834 psF32 *vr = vi - i; 835 psF32 *vg = gauss - i; 836 double g = 0.0; 837 double s = 0.0; 838 for (int n = -i; n < convRange; n++, vr++, vg++) { 839 s += *vg * *vr; 840 g += *vg; 841 } 842 resultX[i] = s / g; 843 } 844 /* If that's all the pixels we have, then we're done already */ 845 if (Nx > Nrange) { 846 /* Smooth middle pixels; if Nx < 2*Nrange, this pass is skipped */ 847 for (int i = Nrange; i < Nx - Nrange; i++, vi++) { 848 psF32 *vr = vi - Nrange; 849 psF32 *vg = gauss - Nrange; 850 double s = 0; 851 for (int n = -Nrange; n < Nrange + 1; n++, vr++, vg++) { 852 s += *vg * *vr; 853 } 854 resultX[i] = s; 855 } 856 /* Smooth last Nrange pixels, with renorm */ 857 // if Nx < 2*Nrange, this pass starts at i == Nrange 858 int xMin = PS_MAX(Nx - Nrange, Nrange); 859 for (int i = xMin; i < Nx; i++, vi++) { 860 psF32 *vr = vi - Nrange; 861 psF32 *vg = gauss - Nrange; 862 double g = 0.0; 863 double s = 0.0; 864 for (int n = -Nrange; n < Nx - i; n++, vr++, vg++) { 865 s += *vg * *vr; 866 g += *vg; 867 } 868 resultX[i] = s / g; 869 } 870 } 871 memcpy(image->data.F32[j], resultX, Nx*sizeof(psF32)); 872 } 873 } 874 875 // this section probably hits the cache poorly for large images, but is probably OK for small ones 876 /* Smooth in Y direction */ 877 { 878 for (int i = 0; i < Nx; i++) { 879 int yMax = PS_MIN(Nrange, Ny); 880 /* Smooth first Nrange pixels, with renorm */ 881 for (int j = 0; j < yMax; j++) { 882 int convRange = PS_MIN(Nrange + 1, Ny - j); 883 psF32 *vg = gauss - j; 884 double g = 0.0; 885 double s = 0.0; 886 for (int n = -j; n < convRange; n++, vg++) { 887 psF32 vr = image->data.F32[j+n][i]; 888 s += *vg * vr; 889 g += *vg; 890 } 891 resultY[j] = s / g; 892 } 893 /* If that's all the pixels we have, then we're done already */ 894 if (Ny > Nrange) { 895 /* Smooth middle pixels */ 896 for (int j = Nrange; j < Ny - Nrange; j++) { 897 psF32 *vg = gauss - Nrange; 898 double s = 0; 899 for (int n = -Nrange; n < Nrange + 1; n++, vg++) { 900 psF32 vr = image->data.F32[j+n][i]; 901 s += *vg * vr; 902 } 903 resultY[j] = s; 904 } 905 /* Smooth last Nrange pixels, with renorm */ 906 // if Ny < 2*Nrange, this pass starts at j == Nrange 907 int yMin = PS_MAX(Ny - Nrange, Nrange); 908 for (int j = yMin; j < Ny; j++) { 909 psF32 *vg = gauss - Nrange; 910 double g = 0.0; 911 double s = 0.0; 912 for (int n = -Nrange; n < Ny - j; n++, vg++) { 913 psF32 vr = image->data.F32[j+n][i]; 914 s += *vg * vr; 915 g += *vg; 916 } 917 resultY[j] = s / g; 918 } 919 } 920 // loop here 921 for (int j = 0; j < Ny; j++) { 922 image->data.F32[j][i] = resultY[j]; 923 } 924 } 925 } 926 return true; 927 } 928 767 929 static bool imageSmoothMaskPixels(psVector *out, const psImage *image, const psImage *mask, 768 930 psImageMaskType maskVal, const psVector *x, const psVector *y, … … 849 1011 850 1012 // Generate normalized gaussian 1013 psVector *gaussNorm = NULL; 851 1014 IMAGE_SMOOTH_GAUSS(gaussNorm, size, sigma, F32); 852 1015 … … 859 1022 860 1023 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTHMASK_PIXELS"); 861 psArrayAdd(job->args, 1, out);862 psArrayAdd(job->args, 1, (psImage*)image);863 psArrayAdd(job->args, 1, (psImage*)mask);1024 psArrayAdd(job->args, 0, out); 1025 psArrayAdd(job->args, 0, (psImage*)image); 1026 psArrayAdd(job->args, 0, (psImage*)mask); 864 1027 PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK); 865 psArrayAdd(job->args, 1, (psVector*)x);866 psArrayAdd(job->args, 1, (psVector*)y);867 psArrayAdd(job->args, 1, gaussNorm);1028 psArrayAdd(job->args, 0, (psVector*)x); 1029 psArrayAdd(job->args, 0, (psVector*)y); 1030 psArrayAdd(job->args, 0, gaussNorm); 868 1031 PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32); 869 1032 PS_ARRAY_ADD_SCALAR(job->args, size, PS_TYPE_S32); … … 876 1039 } 877 1040 } 878 if (!psThreadPoolWait(true )) {1041 if (!psThreadPoolWait(true, true)) { 879 1042 psError(PS_ERR_UNKNOWN, false, "Error waiting for threads."); 880 1043 psFree(gaussNorm); … … 974 1137 975 1138 // Generate normalized gaussian 1139 psVector *gaussNorm = NULL; 976 1140 IMAGE_SMOOTH_GAUSS(gaussNorm, size, sigma, F32); 977 1141 const psF32 *gauss = &gaussNorm->data.F32[size]; // Gaussian convolution kernel … … 1185 1349 1186 1350 // Generate normalized gaussian 1351 psVector *gaussNorm = NULL; 1187 1352 IMAGE_SMOOTH_GAUSS(gaussNorm, size, sigma, F32); 1188 1353 … … 1203 1368 // allocate a job, construct the arguments for this job 1204 1369 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTHMASK_SCANROWS"); 1205 psArrayAdd(job->args, 1, calculation);1206 psArrayAdd(job->args, 1, calcMask);1207 psArrayAdd(job->args, 1, (psImage *) image); // cast away const1208 psArrayAdd(job->args, 1, (psImage *) mask); // cast away const1370 psArrayAdd(job->args, 0, calculation); 1371 psArrayAdd(job->args, 0, calcMask); 1372 psArrayAdd(job->args, 0, (psImage *) image); // cast away const 1373 psArrayAdd(job->args, 0, (psImage *) mask); // cast away const 1209 1374 PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK); 1210 psArrayAdd(job->args, 1, gaussNorm);1375 psArrayAdd(job->args, 0, gaussNorm); 1211 1376 PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32); 1212 1377 PS_ARRAY_ADD_SCALAR(job->args, size, PS_TYPE_S32); … … 1225 1390 } 1226 1391 // wait here for the threaded jobs to finish (NOP if threading is not active) 1227 if (!psThreadPoolWait(true )) {1392 if (!psThreadPoolWait(true, true)) { 1228 1393 psError(PS_ERR_UNKNOWN, false, "Unable to smooth image"); 1229 1394 psFree(calculation); … … 1250 1415 // allocate a job, construct the arguments for this job 1251 1416 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTHMASK_SCANCOLS"); 1252 psArrayAdd(job->args, 1, output);1253 psArrayAdd(job->args, 1, calculation);1254 psArrayAdd(job->args, 1, calcMask);1417 psArrayAdd(job->args, 0, output); 1418 psArrayAdd(job->args, 0, calculation); 1419 psArrayAdd(job->args, 0, calcMask); 1255 1420 PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK); 1256 psArrayAdd(job->args, 1, gaussNorm);1421 psArrayAdd(job->args, 0, gaussNorm); 1257 1422 PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32); 1258 1423 PS_ARRAY_ADD_SCALAR(job->args, size, PS_TYPE_S32); … … 1272 1437 1273 1438 // wait here for the threaded jobs to finish (NOP if threading is not active) 1274 if (!psThreadPoolWait(true )) {1439 if (!psThreadPoolWait(true, true)) { 1275 1440 psError(PS_ERR_UNKNOWN, false, "Unable to smooth image"); 1276 1441 psFree(calculation); … … 1321 1486 1322 1487 /* generate normalized gaussian */ 1488 psVector *gaussnorm = NULL; 1323 1489 IMAGE_SMOOTH_GAUSS(gaussnorm, Nrange, sigma, F32); 1324 1490 psF32 *gauss = &gaussnorm->data.F32[Nrange]; … … 1572 1738 1573 1739 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_CONVOLVE_MASK"); 1574 psArrayAdd(job->args, 1, conv);1575 psArrayAdd(job->args, 1, (psImage*)mask); // Casting away const to put on arguments1740 psArrayAdd(job->args, 0, conv); 1741 psArrayAdd(job->args, 0, (psImage*)mask); // Casting away const to put on arguments 1576 1742 PS_ARRAY_ADD_SCALAR(job->args, start, PS_TYPE_S32); 1577 1743 PS_ARRAY_ADD_SCALAR(job->args, stop, PS_TYPE_S32); … … 1586 1752 } 1587 1753 } 1588 if (!psThreadPoolWait(true )) {1754 if (!psThreadPoolWait(true, true)) { 1589 1755 psError(PS_ERR_UNKNOWN, false, "Error waiting for threads."); 1590 1756 psFree(conv); … … 1607 1773 1608 1774 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_CONVOLVE_MASK"); 1609 psArrayAdd(job->args, 1, out);1610 psArrayAdd(job->args, 1, conv);1775 psArrayAdd(job->args, 0, out); 1776 psArrayAdd(job->args, 0, conv); 1611 1777 PS_ARRAY_ADD_SCALAR(job->args, start, PS_TYPE_S32); 1612 1778 PS_ARRAY_ADD_SCALAR(job->args, stop, PS_TYPE_S32); … … 1621 1787 } 1622 1788 } 1623 if (!psThreadPoolWait(true )) {1789 if (!psThreadPoolWait(true, true)) { 1624 1790 psError(PS_ERR_UNKNOWN, false, "Error waiting for threads."); 1625 1791 psFree(conv);
Note:
See TracChangeset
for help on using the changeset viewer.
