diff options
author | Daniil Kazantsev <dkazanc@hotmail.com> | 2019-03-10 22:23:22 +0000 |
---|---|---|
committer | Daniil Kazantsev <dkazanc@hotmail.com> | 2019-03-10 22:23:22 +0000 |
commit | e2208bfc2ed540065bef2e8e12d914d873464da7 (patch) | |
tree | 36f91247b169ad423ff40a5850b19524f85d1f3e /src | |
parent | 49761c3730e2ddf2ec40c84952572c43e9334ccb (diff) | |
download | regularization-e2208bfc2ed540065bef2e8e12d914d873464da7.tar.gz regularization-e2208bfc2ed540065bef2e8e12d914d873464da7.tar.bz2 regularization-e2208bfc2ed540065bef2e8e12d914d873464da7.tar.xz regularization-e2208bfc2ed540065bef2e8e12d914d873464da7.zip |
all python code updated
Diffstat (limited to 'src')
31 files changed, 2082 insertions, 1585 deletions
diff --git a/src/Core/regularisers_CPU/Diffus4th_order_core.c b/src/Core/regularisers_CPU/Diffus4th_order_core.c index 01f4f64..28ac8a9 100644 --- a/src/Core/regularisers_CPU/Diffus4th_order_core.c +++ b/src/Core/regularisers_CPU/Diffus4th_order_core.c @@ -23,61 +23,85 @@ #define EPS 1.0e-7 /* C-OMP implementation of fourth-order diffusion scheme [1] for piecewise-smooth recovery (2D/3D case) - * The minimisation is performed using explicit scheme. + * The minimisation is performed using explicit scheme. * * Input Parameters: - * 1. Noisy image/volume + * 1. Noisy image/volume * 2. lambda - regularization parameter * 3. Edge-preserving parameter (sigma) - * 4. Number of iterations, for explicit scheme >= 150 is recommended + * 4. Number of iterations, for explicit scheme >= 150 is recommended * 5. tau - time-marching step for the explicit scheme + * 6. eplsilon: tolerance constant * * Output: - * [1] Regularized image/volume + * [1] Regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the paper by * [1] Hajiaboli, M.R., 2011. An anisotropic fourth-order diffusion filter for image noise removal. International Journal of Computer Vision, 92(2), pp.177-191. */ -float Diffus4th_CPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int dimX, int dimY, int dimZ) +float Diffus4th_CPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, float epsil, int dimX, int dimY, int dimZ) { - int i,DimTotal; - float sigmaPar2; - float *W_Lapl=NULL; + int i,DimTotal,j,count; + float sigmaPar2, re, re1; + re = 0.0f; re1 = 0.0f; + count = 0; + float *W_Lapl=NULL, *Output_prev=NULL; sigmaPar2 = sigmaPar*sigmaPar; DimTotal = dimX*dimY*dimZ; - + W_Lapl = calloc(DimTotal, sizeof(float)); - + + if (epsil != 0.0f) Output_prev = calloc(DimTotal, sizeof(float)); + /* copy into output */ copyIm(Input, Output, (long)(dimX), (long)(dimY), (long)(dimZ)); - - if (dimZ == 1) { - /* running 2D diffusion iterations */ + for(i=0; i < iterationsNumb; i++) { + if ((epsil != 0.0f) && (i % 5 == 0)) copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); + + if (dimZ == 1) { + /* running 2D diffusion iterations */ /* Calculating weighted Laplacian */ Weighted_Laplc2D(W_Lapl, Output, sigmaPar2, dimX, dimY); /* Perform iteration step */ Diffusion_update_step2D(Output, Input, W_Lapl, lambdaPar, sigmaPar2, tau, (long)(dimX), (long)(dimY)); - } - } - else { - /* running 3D diffusion iterations */ - for(i=0; i < iterationsNumb; i++) { - /* Calculating weighted Laplacian */ + } + else { + /* running 3D diffusion iterations */ + /* Calculating weighted Laplacian */ Weighted_Laplc3D(W_Lapl, Output, sigmaPar2, dimX, dimY, dimZ); /* Perform iteration step */ Diffusion_update_step3D(Output, Input, W_Lapl, lambdaPar, sigmaPar2, tau, (long)(dimX), (long)(dimY), (long)(dimZ)); - } - } - free(W_Lapl); - return *Output; + } + + /* check early stopping criteria */ + if ((epsil != 0.0f) && (i % 5 == 0)) { + re = 0.0f; re1 = 0.0f; + for(j=0; j<DimTotal; j++) + { + re += powf(Output[j] - Output_prev[j],2); + re1 += powf(Output[j],2); + } + re = sqrtf(re)/sqrtf(re1); + if (re < epsil) count++; + if (count > 3) break; + } + } + free(W_Lapl); + + if (epsil != 0.0f) free(Output_prev); + /*adding info into info_vector */ + infovector[0] = (float)(i); /*iterations number (if stopped earlier based on tolerance)*/ + infovector[1] = re; /* reached tolerance */ + return 0; } /********************************************************************/ /***************************2D Functions*****************************/ /********************************************************************/ float Weighted_Laplc2D(float *W_Lapl, float *U0, float sigma, long dimX, long dimY) -{ +{ long i,j,i1,i2,j1,j2,index; float gradX, gradX_sq, gradY, gradY_sq, gradXX, gradYY, gradXY, xy_2, denom, V_norm, V_orth, c, c_sq; @@ -90,35 +114,35 @@ float Weighted_Laplc2D(float *W_Lapl, float *U0, float sigma, long dimX, long di /* symmetric boundary conditions */ j1 = j+1; if (j1 == dimY) j1 = j-1; j2 = j-1; if (j2 < 0) j2 = j+1; - + index = j*dimX+i; - + gradX = 0.5f*(U0[j*dimX+i2] - U0[j*dimX+i1]); gradX_sq = pow(gradX,2); - + gradY = 0.5f*(U0[j2*dimX+i] - U0[j1*dimX+i]); gradY_sq = pow(gradY,2); - + gradXX = U0[j*dimX+i2] + U0[j*dimX+i1] - 2*U0[index]; gradYY = U0[j2*dimX+i] + U0[j1*dimX+i] - 2*U0[index]; - + gradXY = 0.25f*(U0[j2*dimX+i2] + U0[j1*dimX+i1] - U0[j1*dimX+i2] - U0[j2*dimX+i1]); xy_2 = 2.0f*gradX*gradY*gradXY; - + denom = gradX_sq + gradY_sq; - + if (denom <= EPS) { V_norm = (gradXX*gradX_sq + xy_2 + gradYY*gradY_sq)/EPS; - V_orth = (gradXX*gradY_sq - xy_2 + gradYY*gradX_sq)/EPS; + V_orth = (gradXX*gradY_sq - xy_2 + gradYY*gradX_sq)/EPS; } else { V_norm = (gradXX*gradX_sq + xy_2 + gradYY*gradY_sq)/denom; - V_orth = (gradXX*gradY_sq - xy_2 + gradYY*gradX_sq)/denom; + V_orth = (gradXX*gradY_sq - xy_2 + gradYY*gradX_sq)/denom; } c = 1.0f/(1.0f + denom/sigma); c_sq = c*c; - + W_Lapl[index] = c_sq*V_norm + c*V_orth; } } @@ -140,7 +164,7 @@ float Diffusion_update_step2D(float *Output, float *Input, float *W_Lapl, float j1 = j+1; if (j1 == dimY) j1 = j-1; j2 = j-1; if (j2 < 0) j2 = j+1; index = j*dimX+i; - + gradXXc = W_Lapl[j*dimX+i2] + W_Lapl[j*dimX+i1] - 2*W_Lapl[index]; gradYYc = W_Lapl[j2*dimX+i] + W_Lapl[j1*dimX+i] - 2*W_Lapl[index]; @@ -153,10 +177,10 @@ float Diffusion_update_step2D(float *Output, float *Input, float *W_Lapl, float /***************************3D Functions*****************************/ /********************************************************************/ float Weighted_Laplc3D(float *W_Lapl, float *U0, float sigma, long dimX, long dimY, long dimZ) -{ +{ long i,j,k,i1,i2,j1,j2,k1,k2,index; float gradX, gradX_sq, gradY, gradY_sq, gradXX, gradYY, gradXY, xy_2, denom, V_norm, V_orth, c, c_sq, gradZ, gradZ_sq, gradZZ, gradXZ, gradYZ, xyz_1, xyz_2; - + #pragma omp parallel for shared(W_Lapl) private(i,j,k,i1,i2,j1,j2,k1,k2,index,gradX, gradX_sq, gradY, gradY_sq, gradXX, gradYY, gradXY, xy_2, denom, V_norm, V_orth, c, c_sq, gradZ, gradZ_sq, gradZZ, gradXZ, gradYZ, xyz_1, xyz_2) for(i=0; i<dimX; i++) { /* symmetric boundary conditions */ @@ -166,37 +190,37 @@ float Weighted_Laplc3D(float *W_Lapl, float *U0, float sigma, long dimX, long di /* symmetric boundary conditions */ j1 = j+1; if (j1 == dimY) j1 = j-1; j2 = j-1; if (j2 < 0) j2 = j+1; - + for(k=0; k<dimZ; k++) { /* symmetric boundary conditions */ k1 = k+1; if (k1 == dimZ) k1 = k-1; k2 = k-1; if (k2 < 0) k2 = k+1; - + index = (dimX*dimY)*k + j*dimX+i; - + gradX = 0.5f*(U0[(dimX*dimY)*k + j*dimX+i2] - U0[(dimX*dimY)*k + j*dimX+i1]); gradX_sq = pow(gradX,2); - + gradY = 0.5f*(U0[(dimX*dimY)*k + j2*dimX+i] - U0[(dimX*dimY)*k + j1*dimX+i]); gradY_sq = pow(gradY,2); - + gradZ = 0.5f*(U0[(dimX*dimY)*k2 + j*dimX+i] - U0[(dimX*dimY)*k1 + j*dimX+i]); gradZ_sq = pow(gradZ,2); - + gradXX = U0[(dimX*dimY)*k + j*dimX+i2] + U0[(dimX*dimY)*k + j*dimX+i1] - 2*U0[index]; gradYY = U0[(dimX*dimY)*k + j2*dimX+i] + U0[(dimX*dimY)*k + j1*dimX+i] - 2*U0[index]; gradZZ = U0[(dimX*dimY)*k2 + j*dimX+i] + U0[(dimX*dimY)*k1 + j*dimX+i] - 2*U0[index]; - + gradXY = 0.25f*(U0[(dimX*dimY)*k + j2*dimX+i2] + U0[(dimX*dimY)*k + j1*dimX+i1] - U0[(dimX*dimY)*k + j1*dimX+i2] - U0[(dimX*dimY)*k + j2*dimX+i1]); gradXZ = 0.25f*(U0[(dimX*dimY)*k2 + j*dimX+i2] - U0[(dimX*dimY)*k2+j*dimX+i1] - U0[(dimX*dimY)*k1+j*dimX+i2] + U0[(dimX*dimY)*k1+j*dimX+i1]); gradYZ = 0.25f*(U0[(dimX*dimY)*k2 +j2*dimX+i] - U0[(dimX*dimY)*k2+j1*dimX+i] - U0[(dimX*dimY)*k1+j2*dimX+i] + U0[(dimX*dimY)*k1+j1*dimX+i]); - + xy_2 = 2.0f*gradX*gradY*gradXY; xyz_1 = 2.0f*gradX*gradZ*gradXZ; xyz_2 = 2.0f*gradY*gradZ*gradYZ; - + denom = gradX_sq + gradY_sq + gradZ_sq; - + if (denom <= EPS) { V_norm = (gradXX*gradX_sq + gradYY*gradY_sq + gradZZ*gradZ_sq + xy_2 + xyz_1 + xyz_2)/EPS; V_orth = ((gradY_sq + gradZ_sq)*gradXX + (gradX_sq + gradZ_sq)*gradYY + (gradX_sq + gradY_sq)*gradZZ - xy_2 - xyz_1 - xyz_2)/EPS; @@ -208,7 +232,7 @@ float Weighted_Laplc3D(float *W_Lapl, float *U0, float sigma, long dimX, long di c = 1.0f/(1.0f + denom/sigma); c_sq = c*c; - + W_Lapl[index] = c_sq*V_norm + c*V_orth; } } @@ -230,18 +254,18 @@ float Diffusion_update_step3D(float *Output, float *Input, float *W_Lapl, float /* symmetric boundary conditions */ j1 = j+1; if (j1 == dimY) j1 = j-1; j2 = j-1; if (j2 < 0) j2 = j+1; - + for(k=0; k<dimZ; k++) { /* symmetric boundary conditions */ k1 = k+1; if (k1 == dimZ) k1 = k-1; k2 = k-1; if (k2 < 0) k2 = k+1; - + index = (dimX*dimY)*k + j*dimX+i; - + gradXXc = W_Lapl[(dimX*dimY)*k + j*dimX+i2] + W_Lapl[(dimX*dimY)*k + j*dimX+i1] - 2*W_Lapl[index]; gradYYc = W_Lapl[(dimX*dimY)*k + j2*dimX+i] + W_Lapl[(dimX*dimY)*k + j1*dimX+i] - 2*W_Lapl[index]; gradZZc = W_Lapl[(dimX*dimY)*k2 + j*dimX+i] + W_Lapl[(dimX*dimY)*k1 + j*dimX+i] - 2*W_Lapl[index]; - + Output[index] += tau*(-lambdaPar*(gradXXc + gradYYc + gradZZc) - (Output[index] - Input[index])); } } diff --git a/src/Core/regularisers_CPU/Diffus4th_order_core.h b/src/Core/regularisers_CPU/Diffus4th_order_core.h index d81afcb..e4a8b3e 100644 --- a/src/Core/regularisers_CPU/Diffus4th_order_core.h +++ b/src/Core/regularisers_CPU/Diffus4th_order_core.h @@ -26,26 +26,28 @@ limitations under the License. #include "CCPiDefines.h" /* C-OMP implementation of fourth-order diffusion scheme [1] for piecewise-smooth recovery (2D/3D case) - * The minimisation is performed using explicit scheme. + * The minimisation is performed using explicit scheme. * * Input Parameters: - * 1. Noisy image/volume + * 1. Noisy image/volume * 2. lambda - regularization parameter * 3. Edge-preserving parameter (sigma) - * 4. Number of iterations, for explicit scheme >= 150 is recommended + * 4. Number of iterations, for explicit scheme >= 150 is recommended * 5. tau - time-marching step for explicit scheme + * 6. eplsilon: tolerance constant * * Output: - * [1] Regularized image/volume + * [1] Regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the paper by * [1] Hajiaboli, M.R., 2011. An anisotropic fourth-order diffusion filter for image noise removal. International Journal of Computer Vision, 92(2), pp.177-191. */ - + #ifdef __cplusplus extern "C" { #endif -CCPI_EXPORT float Diffus4th_CPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int dimX, int dimY, int dimZ); +CCPI_EXPORT float Diffus4th_CPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, float epsil, int dimX, int dimY, int dimZ); CCPI_EXPORT float Weighted_Laplc2D(float *W_Lapl, float *U0, float sigma, long dimX, long dimY); CCPI_EXPORT float Diffusion_update_step2D(float *Output, float *Input, float *W_Lapl, float lambdaPar, float sigmaPar2, float tau, long dimX, long dimY); CCPI_EXPORT float Weighted_Laplc3D(float *W_Lapl, float *U0, float sigma, long dimX, long dimY, long dimZ); diff --git a/src/Core/regularisers_CPU/Diffusion_core.c b/src/Core/regularisers_CPU/Diffusion_core.c index b765796..7f06dd8 100644 --- a/src/Core/regularisers_CPU/Diffusion_core.c +++ b/src/Core/regularisers_CPU/Diffusion_core.c @@ -30,48 +30,75 @@ int signNDFc(float x) { } /* C-OMP implementation of linear and nonlinear diffusion with the regularisation model [1,2] (2D/3D case) - * The minimisation is performed using explicit scheme. + * The minimisation is performed using explicit scheme. * * Input Parameters: - * 1. Noisy image/volume + * 1. Noisy image/volume * 2. lambda - regularization parameter * 3. Edge-preserving parameter (sigma), when sigma equals to zero nonlinear diffusion -> linear diffusion - * 4. Number of iterations, for explicit scheme >= 150 is recommended + * 4. Number of iterations, for explicit scheme >= 150 is recommended * 5. tau - time-marching step for explicit scheme * 6. Penalty type: 1 - Huber, 2 - Perona-Malik, 3 - Tukey Biweight - * + * 7. eplsilon - tolerance constant + * Output: - * [1] Regularized image/volume + * [1] Filtered/regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the paper by * [1] Perona, P. and Malik, J., 1990. Scale-space and edge detection using anisotropic diffusion. IEEE Transactions on pattern analysis and machine intelligence, 12(7), pp.629-639. * [2] Black, M.J., Sapiro, G., Marimont, D.H. and Heeger, D., 1998. Robust anisotropic diffusion. IEEE Transactions on image processing, 7(3), pp.421-432. */ -float Diffusion_CPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, int dimX, int dimY, int dimZ) +float Diffusion_CPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, float epsil, int dimX, int dimY, int dimZ) { int i; - float sigmaPar2; + float sigmaPar2, *Output_prev=NULL; sigmaPar2 = sigmaPar/sqrt(2.0f); - + long j, DimTotal; + float re, re1; + re = 0.0f; re1 = 0.0f; + int count = 0; + DimTotal = (long)(dimX*dimY*dimZ); + + if (epsil != 0.0f) Output_prev = calloc(DimTotal, sizeof(float)); + /* copy into output */ copyIm(Input, Output, (long)(dimX), (long)(dimY), (long)(dimZ)); - - if (dimZ == 1) { - /* running 2D diffusion iterations */ + for(i=0; i < iterationsNumb; i++) { + + if ((epsil != 0.0f) && (i % 5 == 0)) copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); + if (dimZ == 1) { + /* running 2D diffusion iterations */ if (sigmaPar == 0.0f) LinearDiff2D(Input, Output, lambdaPar, tau, (long)(dimX), (long)(dimY)); /* linear diffusion (heat equation) */ else NonLinearDiff2D(Input, Output, lambdaPar, sigmaPar2, tau, penaltytype, (long)(dimX), (long)(dimY)); /* nonlinear diffusion */ + } + else { + /* running 3D diffusion iterations */ + if (sigmaPar == 0.0f) LinearDiff3D(Input, Output, lambdaPar, tau, (long)(dimX), (long)(dimY), (long)(dimZ)); + else NonLinearDiff3D(Input, Output, lambdaPar, sigmaPar2, tau, penaltytype, (long)(dimX), (long)(dimY), (long)(dimZ)); + } + /* check early stopping criteria if epsilon not equal zero */ + if ((epsil != 0.0f) && (i % 5 == 0)) { + re = 0.0f; re1 = 0.0f; + for(j=0; j<DimTotal; j++) + { + re += powf(Output[j] - Output_prev[j],2); + re1 += powf(Output[j],2); + } + re = sqrtf(re)/sqrtf(re1); + /* stop if the norm residual is less than the tolerance EPS */ + if (re < epsil) count++; + if (count > 3) break; + } } - } - else { - /* running 3D diffusion iterations */ - for(i=0; i < iterationsNumb; i++) { - if (sigmaPar == 0.0f) LinearDiff3D(Input, Output, lambdaPar, tau, (long)(dimX), (long)(dimY), (long)(dimZ)); - else NonLinearDiff3D(Input, Output, lambdaPar, sigmaPar2, tau, penaltytype, (long)(dimX), (long)(dimY), (long)(dimZ)); - } - } - return *Output; + + free(Output_prev); + /*adding info into info_vector */ + infovector[0] = (float)(i); /*iterations number (if stopped earlier based on tolerance)*/ + infovector[1] = re; /* reached tolerance */ + return 0; } @@ -83,7 +110,7 @@ float LinearDiff2D(float *Input, float *Output, float lambdaPar, float tau, long { long i,j,i1,i2,j1,j2,index; float e,w,n,s,e1,w1,n1,s1; - + #pragma omp parallel for shared(Input) private(index,i,j,i1,i2,j1,j2,e,w,n,s,e1,w1,n1,s1) for(i=0; i<dimX; i++) { /* symmetric boundary conditions (Neuman) */ @@ -94,18 +121,18 @@ float LinearDiff2D(float *Input, float *Output, float lambdaPar, float tau, long j1 = j+1; if (j1 == dimY) j1 = j-1; j2 = j-1; if (j2 < 0) j2 = j+1; index = j*dimX+i; - + e = Output[j*dimX+i1]; w = Output[j*dimX+i2]; n = Output[j1*dimX+i]; s = Output[j2*dimX+i]; - + e1 = e - Output[index]; w1 = w - Output[index]; n1 = n - Output[index]; s1 = s - Output[index]; - - Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1) - (Output[index] - Input[index])); + + Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1) - (Output[index] - Input[index])); }} return *Output; } @@ -115,7 +142,7 @@ float NonLinearDiff2D(float *Input, float *Output, float lambdaPar, float sigmaP { long i,j,i1,i2,j1,j2,index; float e,w,n,s,e1,w1,n1,s1; - + #pragma omp parallel for shared(Input) private(index,i,j,i1,i2,j1,j2,e,w,n,s,e1,w1,n1,s1) for(i=0; i<dimX; i++) { /* symmetric boundary conditions (Neuman) */ @@ -126,28 +153,28 @@ float NonLinearDiff2D(float *Input, float *Output, float lambdaPar, float sigmaP j1 = j+1; if (j1 == dimY) j1 = j-1; j2 = j-1; if (j2 < 0) j2 = j+1; index = j*dimX+i; - + e = Output[j*dimX+i1]; w = Output[j*dimX+i2]; n = Output[j1*dimX+i]; s = Output[j2*dimX+i]; - + e1 = e - Output[index]; w1 = w - Output[index]; n1 = n - Output[index]; s1 = s - Output[index]; - + if (penaltytype == 1){ /* Huber penalty */ if (fabs(e1) > sigmaPar) e1 = signNDFc(e1); else e1 = e1/sigmaPar; - + if (fabs(w1) > sigmaPar) w1 = signNDFc(w1); else w1 = w1/sigmaPar; - + if (fabs(n1) > sigmaPar) n1 = signNDFc(n1); else n1 = n1/sigmaPar; - + if (fabs(s1) > sigmaPar) s1 = signNDFc(s1); else s1 = s1/sigmaPar; } @@ -173,7 +200,7 @@ float NonLinearDiff2D(float *Input, float *Output, float lambdaPar, float sigmaP printf("%s \n", "No penalty function selected! Use 1,2 or 3."); break; } - Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1) - (Output[index] - Input[index])); + Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1) - (Output[index] - Input[index])); }} return *Output; } @@ -185,7 +212,7 @@ float LinearDiff3D(float *Input, float *Output, float lambdaPar, float tau, long { long i,j,k,i1,i2,j1,j2,k1,k2,index; float e,w,n,s,u,d,e1,w1,n1,s1,u1,d1; - + #pragma omp parallel for shared(Input) private(index,i,j,i1,i2,j1,j2,e,w,n,s,e1,w1,n1,s1,k,k1,k2,u1,d1,u,d) for(k=0; k<dimZ; k++) { k1 = k+1; if (k1 == dimZ) k1 = k-1; @@ -199,22 +226,22 @@ for(k=0; k<dimZ; k++) { j1 = j+1; if (j1 == dimY) j1 = j-1; j2 = j-1; if (j2 < 0) j2 = j+1; index = (dimX*dimY)*k + j*dimX+i; - + e = Output[(dimX*dimY)*k + j*dimX+i1]; w = Output[(dimX*dimY)*k + j*dimX+i2]; n = Output[(dimX*dimY)*k + j1*dimX+i]; s = Output[(dimX*dimY)*k + j2*dimX+i]; u = Output[(dimX*dimY)*k1 + j*dimX+i]; d = Output[(dimX*dimY)*k2 + j*dimX+i]; - + e1 = e - Output[index]; w1 = w - Output[index]; n1 = n - Output[index]; s1 = s - Output[index]; u1 = u - Output[index]; d1 = d - Output[index]; - - Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1 + u1 + d1) - (Output[index] - Input[index])); + + Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1 + u1 + d1) - (Output[index] - Input[index])); }}} return *Output; } @@ -223,7 +250,7 @@ float NonLinearDiff3D(float *Input, float *Output, float lambdaPar, float sigmaP { long i,j,k,i1,i2,j1,j2,k1,k2,index; float e,w,n,s,u,d,e1,w1,n1,s1,u1,d1; - + #pragma omp parallel for shared(Input) private(index,i,j,i1,i2,j1,j2,e,w,n,s,e1,w1,n1,s1,k,k1,k2,u1,d1,u,d) for(k=0; k<dimZ; k++) { k1 = k+1; if (k1 == dimZ) k1 = k-1; @@ -237,40 +264,40 @@ for(k=0; k<dimZ; k++) { j1 = j+1; if (j1 == dimY) j1 = j-1; j2 = j-1; if (j2 < 0) j2 = j+1; index = (dimX*dimY)*k + j*dimX+i; - + e = Output[(dimX*dimY)*k + j*dimX+i1]; w = Output[(dimX*dimY)*k + j*dimX+i2]; n = Output[(dimX*dimY)*k + j1*dimX+i]; s = Output[(dimX*dimY)*k + j2*dimX+i]; u = Output[(dimX*dimY)*k1 + j*dimX+i]; d = Output[(dimX*dimY)*k2 + j*dimX+i]; - + e1 = e - Output[index]; w1 = w - Output[index]; n1 = n - Output[index]; s1 = s - Output[index]; u1 = u - Output[index]; d1 = d - Output[index]; - + if (penaltytype == 1){ /* Huber penalty */ if (fabs(e1) > sigmaPar) e1 = signNDFc(e1); else e1 = e1/sigmaPar; - + if (fabs(w1) > sigmaPar) w1 = signNDFc(w1); else w1 = w1/sigmaPar; - + if (fabs(n1) > sigmaPar) n1 = signNDFc(n1); else n1 = n1/sigmaPar; - + if (fabs(s1) > sigmaPar) s1 = signNDFc(s1); else s1 = s1/sigmaPar; - + if (fabs(u1) > sigmaPar) u1 = signNDFc(u1); else u1 = u1/sigmaPar; - + if (fabs(d1) > sigmaPar) d1 = signNDFc(d1); - else d1 = d1/sigmaPar; + else d1 = d1/sigmaPar; } else if (penaltytype == 2) { /* Perona-Malik */ @@ -301,7 +328,7 @@ for(k=0; k<dimZ; k++) { break; } - Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1 + u1 + d1) - (Output[index] - Input[index])); + Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1 + u1 + d1) - (Output[index] - Input[index])); }}} return *Output; } diff --git a/src/Core/regularisers_CPU/Diffusion_core.h b/src/Core/regularisers_CPU/Diffusion_core.h index cc36dad..e394a01 100644 --- a/src/Core/regularisers_CPU/Diffusion_core.h +++ b/src/Core/regularisers_CPU/Diffusion_core.h @@ -27,29 +27,31 @@ limitations under the License. /* C-OMP implementation of linear and nonlinear diffusion with the regularisation model [1,2] (2D/3D case) - * The minimisation is performed using explicit scheme. + * The minimisation is performed using explicit scheme. * * Input Parameters: - * 1. Noisy image/volume + * 1. Noisy image/volume * 2. lambda - regularization parameter * 3. Edge-preserving parameter (sigma), when sigma equals to zero nonlinear diffusion -> linear diffusion - * 4. Number of iterations, for explicit scheme >= 150 is recommended + * 4. Number of iterations, for explicit scheme >= 150 is recommended * 5. tau - time-marching step for explicit scheme * 6. Penalty type: 1 - Huber, 2 - Perona-Malik, 3 - Tukey Biweight - * + * 7. eplsilon - tolerance constant + * Output: - * [1] Regularized image/volume + * [1] Filtered/regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the paper by * [1] Perona, P. and Malik, J., 1990. Scale-space and edge detection using anisotropic diffusion. IEEE Transactions on pattern analysis and machine intelligence, 12(7), pp.629-639. * [2] Black, M.J., Sapiro, G., Marimont, D.H. and Heeger, D., 1998. Robust anisotropic diffusion. IEEE Transactions on image processing, 7(3), pp.421-432. */ - + #ifdef __cplusplus extern "C" { #endif -CCPI_EXPORT float Diffusion_CPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, int dimX, int dimY, int dimZ); +CCPI_EXPORT float Diffusion_CPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, float epsil, int dimX, int dimY, int dimZ); CCPI_EXPORT float LinearDiff2D(float *Input, float *Output, float lambdaPar, float tau, long dimX, long dimY); CCPI_EXPORT float NonLinearDiff2D(float *Input, float *Output, float lambdaPar, float sigmaPar, float tau, int penaltytype, long dimX, long dimY); CCPI_EXPORT float LinearDiff3D(float *Input, float *Output, float lambdaPar, float tau, long dimX, long dimY, long dimZ); diff --git a/src/Core/regularisers_CPU/FGP_TV_core.c b/src/Core/regularisers_CPU/FGP_TV_core.c index 3248867..8b1bc8e 100644 --- a/src/Core/regularisers_CPU/FGP_TV_core.c +++ b/src/Core/regularisers_CPU/FGP_TV_core.c @@ -22,12 +22,12 @@ limitations under the License. /* C-OMP implementation of FGP-TV [1] denoising/regularization model (2D/3D case) * * Input Parameters: - * 1. Noisy image/volume - * 2. lambdaPar - regularization parameter + * 1. Noisy image/volume + * 2. lambdaPar - regularization parameter * 3. Number of iterations - * 4. eplsilon: tolerance constant + * 4. eplsilon: tolerance constant * 5. TV-type: methodTV - 'iso' (0) or 'l1' (1) - * 6. nonneg: 'nonnegativity (0 is OFF by default) + * 6. nonneg: 'nonnegativity (0 is OFF by default) * * Output: * [1] Filtered/regularized image/volume @@ -36,7 +36,7 @@ limitations under the License. * This function is based on the Matlab's code and paper by * [1] Amir Beck and Marc Teboulle, "Fast Gradient-Based Algorithms for Constrained Total Variation Image Denoising and Deblurring Problems" */ - + float TV_FGP_CPU_main(float *Input, float *Output, float *infovector, float lambdaPar, int iterationsNumb, float epsil, int methodTV, int nonneg, int dimX, int dimY, int dimZ) { int ll; @@ -46,44 +46,45 @@ float TV_FGP_CPU_main(float *Input, float *Output, float *infovector, float lamb float tk = 1.0f; float tkp1 =1.0f; int count = 0; - + if (dimZ <= 1) { /*2D case */ float *Output_prev=NULL, *P1=NULL, *P2=NULL, *P1_prev=NULL, *P2_prev=NULL, *R1=NULL, *R2=NULL; DimTotal = (long)(dimX*dimY); - - if (epsil != 0.0f) Output_prev = calloc(DimTotal, sizeof(float)); + + if (epsil != 0.0f) Output_prev = calloc(DimTotal, sizeof(float)); P1 = calloc(DimTotal, sizeof(float)); P2 = calloc(DimTotal, sizeof(float)); P1_prev = calloc(DimTotal, sizeof(float)); P2_prev = calloc(DimTotal, sizeof(float)); R1 = calloc(DimTotal, sizeof(float)); - R2 = calloc(DimTotal, sizeof(float)); - + R2 = calloc(DimTotal, sizeof(float)); + /* begin iterations */ for(ll=0; ll<iterationsNumb; ll++) { - + + if ((epsil != 0.0f) && (ll % 5 == 0)) copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), 1l); /* computing the gradient of the objective function */ Obj_func2D(Input, Output, R1, R2, lambdaPar, (long)(dimX), (long)(dimY)); - + /* apply nonnegativity */ if (nonneg == 1) for(j=0; j<DimTotal; j++) {if (Output[j] < 0.0f) Output[j] = 0.0f;} - + /*Taking a step towards minus of the gradient*/ Grad_func2D(P1, P2, Output, R1, R2, lambdaPar, (long)(dimX), (long)(dimY)); - + /* projection step */ Proj_func2D(P1, P2, methodTV, DimTotal); - + /*updating R and t*/ tkp1 = (1.0f + sqrt(1.0f + 4.0f*tk*tk))*0.5f; Rupd_func2D(P1, P1_prev, P2, P2_prev, R1, R2, tkp1, tk, DimTotal); - + /*storing old values*/ copyIm(P1, P1_prev, (long)(dimX), (long)(dimY), 1l); copyIm(P2, P2_prev, (long)(dimX), (long)(dimY), 1l); tk = tkp1; - + /* check early stopping criteria */ if ((epsil != 0.0f) && (ll % 5 == 0)) { re = 0.0f; re1 = 0.0f; @@ -94,49 +95,49 @@ float TV_FGP_CPU_main(float *Input, float *Output, float *infovector, float lamb } re = sqrtf(re)/sqrtf(re1); if (re < epsil) count++; - if (count > 3) break; - - copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), 1l); + if (count > 3) break; } - } - if (epsil != 0.0f) free(Output_prev); - free(P1); free(P2); free(P1_prev); free(P2_prev); free(R1); free(R2); + } + if (epsil != 0.0f) free(Output_prev); + free(P1); free(P2); free(P1_prev); free(P2_prev); free(R1); free(R2); } else { /*3D case*/ - float *Output_prev=NULL, *P1=NULL, *P2=NULL, *P3=NULL, *P1_prev=NULL, *P2_prev=NULL, *P3_prev=NULL, *R1=NULL, *R2=NULL, *R3=NULL; - DimTotal = (long)(dimX*dimY*dimZ); - + float *Output_prev=NULL, *P1=NULL, *P2=NULL, *P3=NULL, *P1_prev=NULL, *P2_prev=NULL, *P3_prev=NULL, *R1=NULL, *R2=NULL, *R3=NULL; + DimTotal = (long)(dimX*dimY*dimZ); + if (epsil != 0.0f) Output_prev = calloc(DimTotal, sizeof(float)); P1 = calloc(DimTotal, sizeof(float)); P2 = calloc(DimTotal, sizeof(float)); P3 = calloc(DimTotal, sizeof(float)); P1_prev = calloc(DimTotal, sizeof(float)); - P2_prev = calloc(DimTotal, sizeof(float)); - P3_prev = calloc(DimTotal, sizeof(float)); + P2_prev = calloc(DimTotal, sizeof(float)); + P3_prev = calloc(DimTotal, sizeof(float)); R1 = calloc(DimTotal, sizeof(float)); - R2 = calloc(DimTotal, sizeof(float)); - R3 = calloc(DimTotal, sizeof(float)); - + R2 = calloc(DimTotal, sizeof(float)); + R3 = calloc(DimTotal, sizeof(float)); + /* begin iterations */ for(ll=0; ll<iterationsNumb; ll++) { - + + if ((epsil != 0.0f) && (ll % 5 == 0)) copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); + /* computing the gradient of the objective function */ Obj_func3D(Input, Output, R1, R2, R3, lambdaPar, (long)(dimX), (long)(dimY), (long)(dimZ)); - + /* apply nonnegativity */ - if (nonneg == 1) for(j=0; j<DimTotal; j++) {if (Output[j] < 0.0f) Output[j] = 0.0f;} - + if (nonneg == 1) for(j=0; j<DimTotal; j++) {if (Output[j] < 0.0f) Output[j] = 0.0f;} + /*Taking a step towards minus of the gradient*/ Grad_func3D(P1, P2, P3, Output, R1, R2, R3, lambdaPar, (long)(dimX), (long)(dimY), (long)(dimZ)); - + /* projection step */ Proj_func3D(P1, P2, P3, methodTV, DimTotal); - + /*updating R and t*/ tkp1 = (1.0f + sqrt(1.0f + 4.0f*tk*tk))*0.5f; Rupd_func3D(P1, P1_prev, P2, P2_prev, P3, P3_prev, R1, R2, R3, tkp1, tk, DimTotal); - + /* calculate norm - stopping rules*/ if ((epsil != 0.0f) && (ll % 5 == 0)) { re = 0.0f; re1 = 0.0f; @@ -148,26 +149,24 @@ float TV_FGP_CPU_main(float *Input, float *Output, float *infovector, float lamb re = sqrtf(re)/sqrtf(re1); /* stop if the norm residual is less than the tolerance EPS */ if (re < epsil) count++; - if (count > 3) break; - - copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); + if (count > 3) break; } - - /*storing old values*/ + + /*storing old values*/ copyIm(P1, P1_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); copyIm(P2, P2_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); copyIm(P3, P3_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); - tk = tkp1; - } - - if (epsil != 0.0f) free(Output_prev); + tk = tkp1; + } + + if (epsil != 0.0f) free(Output_prev); free(P1); free(P2); free(P3); free(P1_prev); free(P2_prev); free(P3_prev); free(R1); free(R2); free(R3); - } - + } + /*adding info into info_vector */ infovector[0] = (float)(ll); /*iterations number (if stopped earlier based on tolerance)*/ infovector[1] = re; /* reached tolerance */ - + return 0; } @@ -239,7 +238,7 @@ float Rupd_func2D(float *P1, float *P1_old, float *P2, float *P2_old, float *R1, float multip; multip = ((tk-1.0f)/tkp1); #pragma omp parallel for shared(P1,P2,P1_old,P2_old,R1,R2,multip) private(i) - for(i=0; i<DimTotal; i++) { + for(i=0; i<DimTotal; i++) { R1[i] = P1[i] + multip*(P1[i] - P1_old[i]); R2[i] = P2[i] + multip*(P2[i] - P2_old[i]); } @@ -274,7 +273,7 @@ float Grad_func3D(float *P1, float *P2, float *P3, float *D, float *R1, float *R for(i=0; i<dimX; i++) { for(j=0; j<dimY; j++) { for(k=0; k<dimZ; k++) { - index = (dimX*dimY)*k + j*dimX+i; + index = (dimX*dimY)*k + j*dimX+i; /* boundary conditions */ if (i == dimX-1) val1 = 0.0f; else val1 = D[index] - D[(dimX*dimY)*k + j*dimX + (i+1)]; if (j == dimY-1) val2 = 0.0f; else val2 = D[index] - D[(dimX*dimY)*k + (j+1)*dimX + i]; @@ -286,13 +285,13 @@ float Grad_func3D(float *P1, float *P2, float *P3, float *D, float *R1, float *R return 1; } float Proj_func3D(float *P1, float *P2, float *P3, int methTV, long DimTotal) -{ +{ float val1, val2, val3, denom, sq_denom; long i; if (methTV == 0) { /* isotropic TV*/ #pragma omp parallel for shared(P1,P2,P3) private(i,val1,val2,val3,sq_denom) - for(i=0; i<DimTotal; i++) { + for(i=0; i<DimTotal; i++) { denom = powf(P1[i],2) + powf(P2[i],2) + powf(P3[i],2); if (denom > 1.0f) { sq_denom = 1.0f/sqrtf(denom); @@ -301,7 +300,7 @@ float Proj_func3D(float *P1, float *P2, float *P3, int methTV, long DimTotal) P3[i] = P3[i]*sq_denom; } } - } + } else { /* anisotropic TV*/ #pragma omp parallel for shared(P1,P2,P3) private(i,val1,val2,val3) @@ -311,7 +310,7 @@ float Proj_func3D(float *P1, float *P2, float *P3, int methTV, long DimTotal) val3 = fabs(P3[i]); if (val1 < 1.0f) {val1 = 1.0f;} if (val2 < 1.0f) {val2 = 1.0f;} - if (val3 < 1.0f) {val3 = 1.0f;} + if (val3 < 1.0f) {val3 = 1.0f;} P1[i] = P1[i]/val1; P2[i] = P2[i]/val2; P3[i] = P3[i]/val3; diff --git a/src/Core/regularisers_CPU/FGP_dTV_core.c b/src/Core/regularisers_CPU/FGP_dTV_core.c index 17b75ff..4e1e38c 100644 --- a/src/Core/regularisers_CPU/FGP_dTV_core.c +++ b/src/Core/regularisers_CPU/FGP_dTV_core.c @@ -3,8 +3,8 @@ This work is part of the Core Imaging Library developed by Visual Analytics and Imaging System Group of the Science Technology Facilities Council, STFC -Copyright 2017 Daniil Kazantsev -Copyright 2017 Srikanth Nagella, Edoardo Pasca +Copyright 2019 Daniil Kazantsev +Copyright 2019 Srikanth Nagella, Edoardo Pasca Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,155 +29,156 @@ limitations under the License. * 3. lambdaPar - regularization parameter [REQUIRED] * 4. Number of iterations [OPTIONAL] * 5. eplsilon: tolerance constant [OPTIONAL] - * 6. eta: smoothing constant to calculate gradient of the reference [OPTIONAL] * + * 6. eta: smoothing constant to calculate gradient of the reference [OPTIONAL] * * 7. TV-type: methodTV - 'iso' (0) or 'l1' (1) [OPTIONAL] * 8. nonneg: 'nonnegativity (0 is OFF by default) [OPTIONAL] * 9. print information: 0 (off) or 1 (on) [OPTIONAL] * * Output: * [1] Filtered/regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the Matlab's codes and papers by * [1] Amir Beck and Marc Teboulle, "Fast Gradient-Based Algorithms for Constrained Total Variation Image Denoising and Deblurring Problems" * [2] M. J. Ehrhardt and M. M. Betcke, Multi-Contrast MRI Reconstruction with Structure-Guided Total Variation, SIAM Journal on Imaging Sciences 9(3), pp. 1084–1106 */ - -float dTV_FGP_CPU_main(float *Input, float *InputRef, float *Output, float lambdaPar, int iterationsNumb, float epsil, float eta, int methodTV, int nonneg, int printM, int dimX, int dimY, int dimZ) + +float dTV_FGP_CPU_main(float *Input, float *InputRef, float *Output, float *infovector, float lambdaPar, int iterationsNumb, float epsil, float eta, int methodTV, int nonneg, int dimX, int dimY, int dimZ) { - int ll; + int ll; long j, DimTotal; - float re, re1; - float tk = 1.0f; + float re, re1; + re = 0.0f; re1 = 0.0f; + float tk = 1.0f; float tkp1=1.0f; int count = 0; - + + + float *Output_prev=NULL, *P1=NULL, *P2=NULL, *P1_prev=NULL, *P2_prev=NULL, *R1=NULL, *R2=NULL, *InputRef_x=NULL, *InputRef_y=NULL; + DimTotal = (long)(dimX*dimY*dimZ); + + if (epsil != 0.0f) Output_prev = calloc(DimTotal, sizeof(float)); + P1 = calloc(DimTotal, sizeof(float)); + P2 = calloc(DimTotal, sizeof(float)); + P1_prev = calloc(DimTotal, sizeof(float)); + P2_prev = calloc(DimTotal, sizeof(float)); + R1 = calloc(DimTotal, sizeof(float)); + R2 = calloc(DimTotal, sizeof(float)); + InputRef_x = calloc(DimTotal, sizeof(float)); + InputRef_y = calloc(DimTotal, sizeof(float)); + if (dimZ <= 1) { - /*2D case */ - float *Output_prev=NULL, *P1=NULL, *P2=NULL, *P1_prev=NULL, *P2_prev=NULL, *R1=NULL, *R2=NULL, *InputRef_x=NULL, *InputRef_y=NULL; - DimTotal = (long)(dimX*dimY); - - Output_prev = calloc(DimTotal, sizeof(float)); - P1 = calloc(DimTotal, sizeof(float)); - P2 = calloc(DimTotal, sizeof(float)); - P1_prev = calloc(DimTotal, sizeof(float)); - P2_prev = calloc(DimTotal, sizeof(float)); - R1 = calloc(DimTotal, sizeof(float)); - R2 = calloc(DimTotal, sizeof(float)); - InputRef_x = calloc(DimTotal, sizeof(float)); - InputRef_y = calloc(DimTotal, sizeof(float)); - - /* calculate gradient field (smoothed) for the reference image */ + /*2D case */ + /* calculate gradient field (smoothed) for the reference image */ GradNorm_func2D(InputRef, InputRef_x, InputRef_y, eta, (long)(dimX), (long)(dimY)); - + /* begin iterations */ for(ll=0; ll<iterationsNumb; ll++) { - - /*projects a 2D vector field R-1,2 onto the orthogonal complement of another 2D vector field InputRef_xy*/ + + if ((epsil != 0.0f) && (ll % 5 == 0)) copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), 1l); + /*projects a 2D vector field R-1,2 onto the orthogonal complement of another 2D vector field InputRef_xy*/ ProjectVect_func2D(R1, R2, InputRef_x, InputRef_y, (long)(dimX), (long)(dimY)); - + /* computing the gradient of the objective function */ Obj_dfunc2D(Input, Output, R1, R2, lambdaPar, (long)(dimX), (long)(dimY)); - + /* apply nonnegativity */ if (nonneg == 1) for(j=0; j<DimTotal; j++) {if (Output[j] < 0.0f) Output[j] = 0.0f;} - + /*Taking a step towards minus of the gradient*/ Grad_dfunc2D(P1, P2, Output, R1, R2, InputRef_x, InputRef_y, lambdaPar, (long)(dimX), (long)(dimY)); - + /* projection step */ Proj_dfunc2D(P1, P2, methodTV, DimTotal); - + /*updating R and t*/ tkp1 = (1.0f + sqrt(1.0f + 4.0f*tk*tk))*0.5f; Rupd_dfunc2D(P1, P1_prev, P2, P2_prev, R1, R2, tkp1, tk, DimTotal); - - /* check early stopping criteria */ - re = 0.0f; re1 = 0.0f; - for(j=0; j<DimTotal; j++) - { - re += pow(Output[j] - Output_prev[j],2); - re1 += pow(Output[j],2); - } - re = sqrt(re)/sqrt(re1); - if (re < epsil) count++; - if (count > 4) break; - - /*storing old values*/ - copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), 1l); + copyIm(P1, P1_prev, (long)(dimX), (long)(dimY), 1l); copyIm(P2, P2_prev, (long)(dimX), (long)(dimY), 1l); tk = tkp1; + + /* check early stopping criteria */ + if ((epsil != 0.0f) && (ll % 5 == 0)) { + re = 0.0f; re1 = 0.0f; + for(j=0; j<DimTotal; j++) + { + re += powf(Output[j] - Output_prev[j],2); + re1 += powf(Output[j],2); + } + re = sqrtf(re)/sqrtf(re1); + if (re < epsil) count++; + if (count > 3) break; + } } - if (printM == 1) printf("FGP-dTV iterations stopped at iteration %i \n", ll); - free(Output_prev); free(P1); free(P2); free(P1_prev); free(P2_prev); free(R1); free(R2); free(InputRef_x); free(InputRef_y); } else { /*3D case*/ - float *Output_prev=NULL, *P1=NULL, *P2=NULL, *P3=NULL, *P1_prev=NULL, *P2_prev=NULL, *P3_prev=NULL, *R1=NULL, *R2=NULL, *R3=NULL, *InputRef_x=NULL, *InputRef_y=NULL, *InputRef_z=NULL; - DimTotal = (long)(dimX*dimY*dimZ); - - Output_prev = calloc(DimTotal, sizeof(float)); - P1 = calloc(DimTotal, sizeof(float)); - P2 = calloc(DimTotal, sizeof(float)); + float *P3=NULL, *P3_prev=NULL, *R3=NULL, *InputRef_z=NULL; + P3 = calloc(DimTotal, sizeof(float)); - P1_prev = calloc(DimTotal, sizeof(float)); - P2_prev = calloc(DimTotal, sizeof(float)); P3_prev = calloc(DimTotal, sizeof(float)); - R1 = calloc(DimTotal, sizeof(float)); - R2 = calloc(DimTotal, sizeof(float)); - R3 = calloc(DimTotal, sizeof(float)); - InputRef_x = calloc(DimTotal, sizeof(float)); - InputRef_y = calloc(DimTotal, sizeof(float)); - InputRef_z = calloc(DimTotal, sizeof(float)); + R3 = calloc(DimTotal, sizeof(float)); + InputRef_z = calloc(DimTotal, sizeof(float)); /* calculate gradient field (smoothed) for the reference volume */ GradNorm_func3D(InputRef, InputRef_x, InputRef_y, InputRef_z, eta, (long)(dimX), (long)(dimY), (long)(dimZ)); - + /* begin iterations */ for(ll=0; ll<iterationsNumb; ll++) { - /*projects a 3D vector field R-1,2,3 onto the orthogonal complement of another 3D vector field InputRef_xyz*/ + if ((epsil != 0.0f) && (ll % 5 == 0)) copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); + + /*projects a 3D vector field R-1,2,3 onto the orthogonal complement of another 3D vector field InputRef_xyz*/ ProjectVect_func3D(R1, R2, R3, InputRef_x, InputRef_y, InputRef_z, (long)(dimX), (long)(dimY), (long)(dimZ)); - + /* computing the gradient of the objective function */ Obj_dfunc3D(Input, Output, R1, R2, R3, lambdaPar, (long)(dimX), (long)(dimY), (long)(dimZ)); - + /* apply nonnegativity */ - if (nonneg == 1) for(j=0; j<DimTotal; j++) {if (Output[j] < 0.0f) Output[j] = 0.0f;} - + if (nonneg == 1) for(j=0; j<DimTotal; j++) {if (Output[j] < 0.0f) Output[j] = 0.0f;} + /*Taking a step towards minus of the gradient*/ Grad_dfunc3D(P1, P2, P3, Output, R1, R2, R3, InputRef_x, InputRef_y, InputRef_z, lambdaPar, (long)(dimX), (long)(dimY), (long)(dimZ)); - + /* projection step */ Proj_dfunc3D(P1, P2, P3, methodTV, DimTotal); - + /*updating R and t*/ tkp1 = (1.0f + sqrt(1.0f + 4.0f*tk*tk))*0.5f; Rupd_dfunc3D(P1, P1_prev, P2, P2_prev, P3, P3_prev, R1, R2, R3, tkp1, tk, DimTotal); - - /* calculate norm - stopping rules*/ - re = 0.0f; re1 = 0.0f; - for(j=0; j<DimTotal; j++) - { - re += pow(Output[j] - Output_prev[j],2); - re1 += pow(Output[j],2); - } - re = sqrt(re)/sqrt(re1); - /* stop if the norm residual is less than the tolerance EPS */ - if (re < epsil) count++; - if (count > 4) break; - - /*storing old values*/ - copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); + + /*storing old values*/ copyIm(P1, P1_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); copyIm(P2, P2_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); copyIm(P3, P3_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); - tk = tkp1; - } - if (printM == 1) printf("FGP-dTV iterations stopped at iteration %i \n", ll); - free(Output_prev); free(P1); free(P2); free(P3); free(P1_prev); free(P2_prev); free(P3_prev); free(R1); free(R2); free(R3); free(InputRef_x); free(InputRef_y); free(InputRef_z); + tk = tkp1; + + /* check early stopping criteria */ + if ((epsil != 0.0f) && (ll % 5 == 0)) { + re = 0.0f; re1 = 0.0f; + for(j=0; j<DimTotal; j++) + { + re += powf(Output[j] - Output_prev[j],2); + re1 += powf(Output[j],2); + } + re = sqrtf(re)/sqrtf(re1); + if (re < epsil) count++; + if (count > 3) break; + } + } + + free(P3); free(P3_prev); free(R3); free(InputRef_z); } - return *Output; + if (epsil != 0.0f) free(Output_prev); + free(P1); free(P2); free(P1_prev); free(P2_prev); free(R1); free(R2); free(InputRef_x); free(InputRef_y); + + /*adding info into info_vector */ + infovector[0] = (float)(ll); /*iterations number (if stopped earlier based on tolerance)*/ + infovector[1] = re; /* reached tolerance */ + + return 0; } @@ -248,11 +249,11 @@ float Grad_dfunc2D(float *P1, float *P2, float *D, float *R1, float *R2, float * /* boundary conditions */ if (i == dimX-1) val1 = 0.0f; else val1 = D[index] - D[j*dimX + (i+1)]; if (j == dimY-1) val2 = 0.0f; else val2 = D[index] - D[(j+1)*dimX + i]; - + in_prod = val1*B_x[index] + val2*B_y[index]; /* calculate inner product */ val1 = val1 - in_prod*B_x[index]; val2 = val2 - in_prod*B_y[index]; - + P1[index] = R1[index] + multip*val1; P2[index] = R2[index] + multip*val2; @@ -295,7 +296,7 @@ float Rupd_dfunc2D(float *P1, float *P1_old, float *P2, float *P2_old, float *R1 float multip; multip = ((tk-1.0f)/tkp1); #pragma omp parallel for shared(P1,P2,P1_old,P2_old,R1,R2,multip) private(i) - for(i=0; i<DimTotal; i++) { + for(i=0; i<DimTotal; i++) { R1[i] = P1[i] + multip*(P1[i] - P1_old[i]); R2[i] = P2[i] + multip*(P2[i] - P2_old[i]); } @@ -314,12 +315,12 @@ float GradNorm_func3D(float *B, float *B_x, float *B_y, float *B_z, float eta, l for(j=0; j<dimY; j++) { for(k=0; k<dimZ; k++) { index = (dimX*dimY)*k + j*dimX+i; - + /* zero boundary conditions */ if (i == dimX-1) {val1 = 0.0f;} else {val1 = B[(dimX*dimY)*k + j*dimX+(i+1)];} if (j == dimY-1) {val2 = 0.0f;} else {val2 = B[(dimX*dimY)*k + (j+1)*dimX+i];} if (k == dimZ-1) {val3 = 0.0f;} else {val3 = B[(dimX*dimY)*(k+1) + (j)*dimX+i];} - + gradX = val1 - B[index]; gradY = val2 - B[index]; gradZ = val3 - B[index]; @@ -375,17 +376,17 @@ float Grad_dfunc3D(float *P1, float *P2, float *P3, float *D, float *R1, float * for(i=0; i<dimX; i++) { for(j=0; j<dimY; j++) { for(k=0; k<dimZ; k++) { - index = (dimX*dimY)*k + j*dimX+i; + index = (dimX*dimY)*k + j*dimX+i; /* boundary conditions */ if (i == dimX-1) val1 = 0.0f; else val1 = D[index] - D[(dimX*dimY)*k + j*dimX + (i+1)]; if (j == dimY-1) val2 = 0.0f; else val2 = D[index] - D[(dimX*dimY)*k + (j+1)*dimX + i]; if (k == dimZ-1) val3 = 0.0f; else val3 = D[index] - D[(dimX*dimY)*(k+1) + j*dimX + i]; - + in_prod = val1*B_x[index] + val2*B_y[index] + val3*B_z[index]; /* calculate inner product */ val1 = val1 - in_prod*B_x[index]; val2 = val2 - in_prod*B_y[index]; val3 = val3 - in_prod*B_z[index]; - + P1[index] = R1[index] + multip*val1; P2[index] = R2[index] + multip*val2; P3[index] = R3[index] + multip*val3; @@ -393,13 +394,13 @@ float Grad_dfunc3D(float *P1, float *P2, float *P3, float *D, float *R1, float * return 1; } float Proj_dfunc3D(float *P1, float *P2, float *P3, int methTV, long DimTotal) -{ +{ float val1, val2, val3, denom, sq_denom; long i; if (methTV == 0) { /* isotropic TV*/ #pragma omp parallel for shared(P1,P2,P3) private(i,val1,val2,val3,sq_denom) - for(i=0; i<DimTotal; i++) { + for(i=0; i<DimTotal; i++) { denom = powf(P1[i],2) + powf(P2[i],2) + powf(P3[i],2); if (denom > 1.0f) { sq_denom = 1.0f/sqrtf(denom); @@ -408,7 +409,7 @@ float Proj_dfunc3D(float *P1, float *P2, float *P3, int methTV, long DimTotal) P3[i] = P3[i]*sq_denom; } } - } + } else { /* anisotropic TV*/ #pragma omp parallel for shared(P1,P2,P3) private(i,val1,val2,val3) @@ -418,7 +419,7 @@ float Proj_dfunc3D(float *P1, float *P2, float *P3, int methTV, long DimTotal) val3 = fabs(P3[i]); if (val1 < 1.0f) {val1 = 1.0f;} if (val2 < 1.0f) {val2 = 1.0f;} - if (val3 < 1.0f) {val3 = 1.0f;} + if (val3 < 1.0f) {val3 = 1.0f;} P1[i] = P1[i]/val1; P2[i] = P2[i]/val2; P3[i] = P3[i]/val3; diff --git a/src/Core/regularisers_CPU/FGP_dTV_core.h b/src/Core/regularisers_CPU/FGP_dTV_core.h index 442dd30..9ace06d 100644 --- a/src/Core/regularisers_CPU/FGP_dTV_core.h +++ b/src/Core/regularisers_CPU/FGP_dTV_core.h @@ -36,23 +36,24 @@ limitations under the License. * 3. lambdaPar - regularization parameter [REQUIRED] * 4. Number of iterations [OPTIONAL] * 5. eplsilon: tolerance constant [OPTIONAL] - * 6. eta: smoothing constant to calculate gradient of the reference [OPTIONAL] * + * 6. eta: smoothing constant to calculate gradient of the reference [OPTIONAL] * * 7. TV-type: methodTV - 'iso' (0) or 'l1' (1) [OPTIONAL] * 8. nonneg: 'nonnegativity (0 is OFF by default) [OPTIONAL] * 9. print information: 0 (off) or 1 (on) [OPTIONAL] * * Output: * [1] Filtered/regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the Matlab's codes and papers by * [1] Amir Beck and Marc Teboulle, "Fast Gradient-Based Algorithms for Constrained Total Variation Image Denoising and Deblurring Problems" * [2] M. J. Ehrhardt and M. M. Betcke, Multi-Contrast MRI Reconstruction with Structure-Guided Total Variation, SIAM Journal on Imaging Sciences 9(3), pp. 1084–1106 */ - + #ifdef __cplusplus extern "C" { #endif -CCPI_EXPORT float dTV_FGP_CPU_main(float *Input, float *InputRef, float *Output, float lambdaPar, int iterationsNumb, float epsil, float eta, int methodTV, int nonneg, int printM, int dimX, int dimY, int dimZ); +CCPI_EXPORT float dTV_FGP_CPU_main(float *Input, float *InputRef, float *Output, float *infovector, float lambdaPar, int iterationsNumb, float epsil, float eta, int methodTV, int nonneg, int dimX, int dimY, int dimZ); CCPI_EXPORT float GradNorm_func2D(float *B, float *B_x, float *B_y, float eta, long dimX, long dimY); CCPI_EXPORT float ProjectVect_func2D(float *R1, float *R2, float *B_x, float *B_y, long dimX, long dimY); diff --git a/src/Core/regularisers_CPU/LLT_ROF_core.c b/src/Core/regularisers_CPU/LLT_ROF_core.c index f9fea66..1064340 100644 --- a/src/Core/regularisers_CPU/LLT_ROF_core.c +++ b/src/Core/regularisers_CPU/LLT_ROF_core.c @@ -74,10 +74,12 @@ float LLT_ROF_CPU_main(float *Input, float *Output, float *infovector, float lam if (epsil != 0.0f) Output_prev = calloc(DimTotal, sizeof(float)); for(ll = 0; ll < iterationsNumb; ll++) { + if ((epsil != 0.0f) && (ll % 5 == 0)) copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); + if (dimZ == 1) { - /* 2D case */ - /****************ROF******************/ - /* calculate first-order differences */ + /* 2D case */ + /****************ROF******************/ + /* calculate first-order differences */ D1_func_ROF(Output, D1_ROF, (long)(dimX), (long)(dimY), 1l); D2_func_ROF(Output, D2_ROF, (long)(dimX), (long)(dimY), 1l); /****************LLT******************/ @@ -87,8 +89,8 @@ float LLT_ROF_CPU_main(float *Input, float *Output, float *infovector, float lam Update2D_LLT_ROF(Input, Output, D1_LLT, D2_LLT, D1_ROF, D2_ROF, lambdaROF, lambdaLLT, tau, (long)(dimX), (long)(dimY), 1l); } else { - /* 3D case */ - /* calculate first-order differences */ + /* 3D case */ + /* calculate first-order differences */ D1_func_ROF(Output, D1_ROF, (long)(dimX), (long)(dimY), (long)(dimZ)); D2_func_ROF(Output, D2_ROF, (long)(dimX), (long)(dimY), (long)(dimZ)); D3_func_ROF(Output, D3_ROF, (long)(dimX), (long)(dimY), (long)(dimZ)); @@ -110,7 +112,6 @@ float LLT_ROF_CPU_main(float *Input, float *Output, float *infovector, float lam re = sqrtf(re)/sqrtf(re1); if (re < epsil) count++; if (count > 3) break; - copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); } } /*end of iterations*/ diff --git a/src/Core/regularisers_CPU/ROF_TV_core.c b/src/Core/regularisers_CPU/ROF_TV_core.c index 8ea2552..6d23eef 100644 --- a/src/Core/regularisers_CPU/ROF_TV_core.c +++ b/src/Core/regularisers_CPU/ROF_TV_core.c @@ -31,16 +31,16 @@ int sign(float x) { /* C-OMP implementation of ROF-TV denoising/regularization model [1] (2D/3D case) * - * + * * Input Parameters: * 1. Noisy image/volume [REQUIRED] * 2. lambda - regularization parameter [REQUIRED] * 3. tau - marching step for explicit scheme, ~1 is recommended [REQUIRED] * 4. Number of iterations, for explicit scheme >= 150 is recommended [REQUIRED] - * 5. eplsilon: tolerance constant + * 5. eplsilon: tolerance constant * * Output: - * [1] Regularized image/volume + * [1] Regularized image/volume * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the paper by @@ -54,26 +54,28 @@ float TV_ROF_CPU_main(float *Input, float *Output, float *infovector, float lamb float re, re1; re = 0.0f; re1 = 0.0f; int count = 0; - int i; + int i; long DimTotal,j; - DimTotal = (long)(dimX*dimY*dimZ); - + DimTotal = (long)(dimX*dimY*dimZ); + D1 = calloc(DimTotal, sizeof(float)); D2 = calloc(DimTotal, sizeof(float)); D3 = calloc(DimTotal, sizeof(float)); - + /* copy into output */ copyIm(Input, Output, (long)(dimX), (long)(dimY), (long)(dimZ)); if (epsil != 0.0f) Output_prev = calloc(DimTotal, sizeof(float)); - + /* start TV iterations */ - for(i=0; i < iterationsNumb; i++) { + for(i=0; i < iterationsNumb; i++) { + if ((epsil != 0.0f) && (i % 5 == 0)) copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); + /* calculate differences */ D1_func(Output, D1, (long)(dimX), (long)(dimY), (long)(dimZ)); D2_func(Output, D2, (long)(dimX), (long)(dimY), (long)(dimZ)); - if (dimZ > 1) D3_func(Output, D3, (long)(dimX), (long)(dimY), (long)(dimZ)); + if (dimZ > 1) D3_func(Output, D3, (long)(dimX), (long)(dimY), (long)(dimZ)); TV_kernel(D1, D2, D3, Output, Input, lambdaPar, tau, (long)(dimX), (long)(dimY), (long)(dimZ)); - + /* check early stopping criteria */ if ((epsil != 0.0f) && (i % 5 == 0)) { re = 0.0f; re1 = 0.0f; @@ -84,17 +86,16 @@ float TV_ROF_CPU_main(float *Input, float *Output, float *infovector, float lamb } re = sqrtf(re)/sqrtf(re1); if (re < epsil) count++; - if (count > 3) break; - copyIm(Output, Output_prev, (long)(dimX), (long)(dimY), (long)(dimZ)); - } - } + if (count > 3) break; + } + } free(D1);free(D2); free(D3); - if (epsil != 0.0f) free(Output_prev); - + if (epsil != 0.0f) free(Output_prev); + /*adding info into info_vector */ infovector[0] = (float)(i); /*iterations number (if stopped earlier based on tolerance)*/ infovector[1] = re; /* reached tolerance */ - + return 0; } @@ -103,7 +104,7 @@ float D1_func(float *A, float *D1, long dimX, long dimY, long dimZ) { float NOMx_1, NOMy_1, NOMy_0, NOMz_1, NOMz_0, denom1, denom2,denom3, T1; long i,j,k,i1,i2,k1,j1,j2,k2,index; - + if (dimZ > 1) { #pragma omp parallel for shared (A, D1, dimX, dimY, dimZ) private(index, i, j, k, i1, j1, k1, i2, j2, k2, NOMx_1,NOMy_1,NOMy_0,NOMz_1,NOMz_0,denom1,denom2,denom3,T1) for(j=0; j<dimY; j++) { @@ -116,18 +117,18 @@ float D1_func(float *A, float *D1, long dimX, long dimY, long dimZ) j1 = j + 1; if (j1 >= dimY) j1 = j-1; j2 = j - 1; if (j2 < 0) j2 = j+1; k1 = k + 1; if (k1 >= dimZ) k1 = k-1; - k2 = k - 1; if (k2 < 0) k2 = k+1; - + k2 = k - 1; if (k2 < 0) k2 = k+1; + /* Forward-backward differences */ NOMx_1 = A[(dimX*dimY)*k + j1*dimX + i] - A[index]; /* x+ */ NOMy_1 = A[(dimX*dimY)*k + j*dimX + i1] - A[index]; /* y+ */ /*NOMx_0 = (A[(i)*dimY + j] - A[(i2)*dimY + j]); */ /* x- */ NOMy_0 = A[index] - A[(dimX*dimY)*k + j*dimX + i2]; /* y- */ - + NOMz_1 = A[(dimX*dimY)*k1 + j*dimX + i] - A[index]; /* z+ */ NOMz_0 = A[index] - A[(dimX*dimY)*k2 + j*dimX + i]; /* z- */ - - + + denom1 = NOMx_1*NOMx_1; denom2 = 0.5f*(sign(NOMy_1) + sign(NOMy_0))*(MIN(fabs(NOMy_1),fabs(NOMy_0))); denom2 = denom2*denom2; @@ -147,13 +148,13 @@ float D1_func(float *A, float *D1, long dimX, long dimY, long dimZ) i2 = i - 1; if (i2 < 0) i2 = i+1; j1 = j + 1; if (j1 >= dimY) j1 = j-1; j2 = j - 1; if (j2 < 0) j2 = j+1; - + /* Forward-backward differences */ NOMx_1 = A[j1*dimX + i] - A[index]; /* x+ */ NOMy_1 = A[j*dimX + i1] - A[index]; /* y+ */ /*NOMx_0 = (A[(i)*dimY + j] - A[(i2)*dimY + j]); */ /* x- */ NOMy_0 = A[index] - A[(j)*dimX + i2]; /* y- */ - + denom1 = NOMx_1*NOMx_1; denom2 = 0.5f*(sign(NOMy_1) + sign(NOMy_0))*(MIN(fabs(NOMy_1),fabs(NOMy_0))); denom2 = denom2*denom2; @@ -168,7 +169,7 @@ float D2_func(float *A, float *D2, long dimX, long dimY, long dimZ) { float NOMx_1, NOMy_1, NOMx_0, NOMz_1, NOMz_0, denom1, denom2, denom3, T2; long i,j,k,i1,i2,k1,j1,j2,k2,index; - + if (dimZ > 1) { #pragma omp parallel for shared (A, D2, dimX, dimY, dimZ) private(index, i, j, k, i1, j1, k1, i2, j2, k2, NOMx_1, NOMy_1, NOMx_0, NOMz_1, NOMz_0, denom1, denom2, denom3, T2) for(j=0; j<dimY; j++) { @@ -181,16 +182,16 @@ float D2_func(float *A, float *D2, long dimX, long dimY, long dimZ) j1 = j + 1; if (j1 >= dimY) j1 = j-1; j2 = j - 1; if (j2 < 0) j2 = j+1; k1 = k + 1; if (k1 >= dimZ) k1 = k-1; - k2 = k - 1; if (k2 < 0) k2 = k+1; - + k2 = k - 1; if (k2 < 0) k2 = k+1; + /* Forward-backward differences */ NOMx_1 = A[(dimX*dimY)*k + (j1)*dimX + i] - A[index]; /* x+ */ NOMy_1 = A[(dimX*dimY)*k + (j)*dimX + i1] - A[index]; /* y+ */ NOMx_0 = A[index] - A[(dimX*dimY)*k + (j2)*dimX + i]; /* x- */ NOMz_1 = A[(dimX*dimY)*k1 + j*dimX + i] - A[index]; /* z+ */ NOMz_0 = A[index] - A[(dimX*dimY)*k2 + (j)*dimX + i]; /* z- */ - - + + denom1 = NOMy_1*NOMy_1; denom2 = 0.5f*(sign(NOMx_1) + sign(NOMx_0))*(MIN(fabs(NOMx_1),fabs(NOMx_0))); denom2 = denom2*denom2; @@ -210,13 +211,13 @@ float D2_func(float *A, float *D2, long dimX, long dimY, long dimZ) i2 = i - 1; if (i2 < 0) i2 = i+1; j1 = j + 1; if (j1 >= dimY) j1 = j-1; j2 = j - 1; if (j2 < 0) j2 = j+1; - + /* Forward-backward differences */ NOMx_1 = A[j1*dimX + i] - A[index]; /* x+ */ NOMy_1 = A[j*dimX + i1] - A[index]; /* y+ */ NOMx_0 = A[index] - A[j2*dimX + i]; /* x- */ /*NOMy_0 = A[(i)*dimY + j] - A[(i)*dimY + j2]; */ /* y- */ - + denom1 = NOMy_1*NOMy_1; denom2 = 0.5f*(sign(NOMx_1) + sign(NOMx_0))*(MIN(fabs(NOMx_1),fabs(NOMx_0))); denom2 = denom2*denom2; @@ -232,7 +233,7 @@ float D3_func(float *A, float *D3, long dimX, long dimY, long dimZ) { float NOMx_1, NOMy_1, NOMx_0, NOMy_0, NOMz_1, denom1, denom2, denom3, T3; long index,i,j,k,i1,i2,k1,j1,j2,k2; - + #pragma omp parallel for shared (A, D3, dimX, dimY, dimZ) private(index, i, j, k, i1, j1, k1, i2, j2, k2, NOMx_1, NOMy_1, NOMy_0, NOMx_0, NOMz_1, denom1, denom2, denom3, T3) for(j=0; j<dimY; j++) { for(i=0; i<dimX; i++) { @@ -245,7 +246,7 @@ float D3_func(float *A, float *D3, long dimX, long dimY, long dimZ) j2 = j - 1; if (j2 < 0) j2 = j+1; k1 = k + 1; if (k1 >= dimZ) k1 = k-1; k2 = k - 1; if (k2 < 0) k2 = k+1; - + /* Forward-backward differences */ NOMx_1 = A[(dimX*dimY)*k + (j1)*dimX + i] - A[index]; /* x+ */ NOMy_1 = A[(dimX*dimY)*k + (j)*dimX + i1] - A[index]; /* y+ */ @@ -253,7 +254,7 @@ float D3_func(float *A, float *D3, long dimX, long dimY, long dimZ) NOMx_0 = A[index] - A[(dimX*dimY)*k + (j2)*dimX + i]; /* x- */ NOMz_1 = A[(dimX*dimY)*k1 + j*dimX + i] - A[index]; /* z+ */ /*NOMz_0 = A[(dimX*dimY)*k + (i)*dimY + j] - A[(dimX*dimY)*k2 + (i)*dimY + j]; */ /* z- */ - + denom1 = NOMz_1*NOMz_1; denom2 = 0.5f*(sign(NOMx_1) + sign(NOMx_0))*(MIN(fabs(NOMx_1),fabs(NOMx_0))); denom2 = denom2*denom2; @@ -270,7 +271,7 @@ float TV_kernel(float *D1, float *D2, float *D3, float *B, float *A, float lambd { float dv1, dv2, dv3; long index,i,j,k,i1,i2,k1,j1,j2,k2; - + if (dimZ > 1) { #pragma omp parallel for shared (D1, D2, D3, B, dimX, dimY, dimZ) private(index, i, j, k, i1, j1, k1, i2, j2, k2, dv1,dv2,dv3) for(j=0; j<dimY; j++) { @@ -284,13 +285,13 @@ float TV_kernel(float *D1, float *D2, float *D3, float *B, float *A, float lambd j2 = j - 1; if (j2 < 0) j2 = j+1; k1 = k + 1; if (k1 >= dimZ) k1 = k-1; k2 = k - 1; if (k2 < 0) k2 = k+1; - + /*divergence components */ dv1 = D1[index] - D1[(dimX*dimY)*k + j2*dimX+i]; dv2 = D2[index] - D2[(dimX*dimY)*k + j*dimX+i2]; dv3 = D3[index] - D3[(dimX*dimY)*k2 + j*dimX+i]; - - B[index] += tau*(lambda*(dv1 + dv2 + dv3) - (B[index] - A[index])); + + B[index] += tau*(lambda*(dv1 + dv2 + dv3) - (B[index] - A[index])); }}} } else { @@ -303,7 +304,7 @@ float TV_kernel(float *D1, float *D2, float *D3, float *B, float *A, float lambd i2 = i - 1; if (i2 < 0) i2 = i+1; j1 = j + 1; if (j1 >= dimY) j1 = j-1; j2 = j - 1; if (j2 < 0) j2 = j+1; - + /* divergence components */ dv1 = D1[index] - D1[j2*dimX + i]; dv2 = D2[index] - D2[j*dimX + i2]; diff --git a/src/Core/regularisers_CPU/SB_TV_core.c b/src/Core/regularisers_CPU/SB_TV_core.c index 07ed9b0..8d80787 100755 --- a/src/Core/regularisers_CPU/SB_TV_core.c +++ b/src/Core/regularisers_CPU/SB_TV_core.c @@ -37,7 +37,7 @@ limitations under the License. float SB_TV_CPU_main(float *Input, float *Output, float *infovector, float mu, int iter, float epsil, int methodTV, int dimX, int dimY, int dimZ) { - int ll; + int ll; long j, DimTotal; float re, re1, lambda; re = 0.0f; re1 = 0.0f; diff --git a/src/Core/regularisers_CPU/TGV_core.c b/src/Core/regularisers_CPU/TGV_core.c index 136e0bd..f43b56a 100644 --- a/src/Core/regularisers_CPU/TGV_core.c +++ b/src/Core/regularisers_CPU/TGV_core.c @@ -29,131 +29,168 @@ * 4. parameter to control the second-order term (alpha0) * 5. Number of Chambolle-Pock (Primal-Dual) iterations * 6. Lipshitz constant (default is 12) + * 7. eplsilon: tolerance constant * * Output: - * Filtered/regularised image/volume + * [1] Filtered/regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * References: * [1] K. Bredies "Total Generalized Variation" * */ -float TGV_main(float *U0, float *U, float lambda, float alpha1, float alpha0, int iter, float L2, int dimX, int dimY, int dimZ) +float TGV_main(float *U0, float *U, float *infovector, float lambda, float alpha1, float alpha0, int iter, float L2, float epsil, int dimX, int dimY, int dimZ) { long DimTotal; - int ll; + int ll, j; + float re, re1; + re = 0.0f; re1 = 0.0f; + int count = 0; float *U_old, *P1, *P2, *Q1, *Q2, *Q3, *V1, *V1_old, *V2, *V2_old, tau, sigma; - + DimTotal = (long)(dimX*dimY*dimZ); copyIm(U0, U, (long)(dimX), (long)(dimY), (long)(dimZ)); /* initialize */ tau = pow(L2,-0.5); sigma = pow(L2,-0.5); - + /* dual variables */ P1 = calloc(DimTotal, sizeof(float)); P2 = calloc(DimTotal, sizeof(float)); - + Q1 = calloc(DimTotal, sizeof(float)); Q2 = calloc(DimTotal, sizeof(float)); Q3 = calloc(DimTotal, sizeof(float)); - + U_old = calloc(DimTotal, sizeof(float)); - + V1 = calloc(DimTotal, sizeof(float)); V1_old = calloc(DimTotal, sizeof(float)); V2 = calloc(DimTotal, sizeof(float)); V2_old = calloc(DimTotal, sizeof(float)); - + if (dimZ == 1) { /*2D case*/ - + /* Primal-dual iterations begin here */ for(ll = 0; ll < iter; ll++) { - + /* Calculate Dual Variable P */ DualP_2D(U, V1, V2, P1, P2, (long)(dimX), (long)(dimY), sigma); - + /*Projection onto convex set for P*/ ProjP_2D(P1, P2, (long)(dimX), (long)(dimY), alpha1); - + /* Calculate Dual Variable Q */ DualQ_2D(V1, V2, Q1, Q2, Q3, (long)(dimX), (long)(dimY), sigma); - + /*Projection onto convex set for Q*/ ProjQ_2D(Q1, Q2, Q3, (long)(dimX), (long)(dimY), alpha0); - + /*saving U into U_old*/ copyIm(U, U_old, (long)(dimX), (long)(dimY), 1l); - + /*adjoint operation -> divergence and projection of P*/ DivProjP_2D(U, U0, P1, P2, (long)(dimX), (long)(dimY), lambda, tau); - + /*get updated solution U*/ newU(U, U_old, (long)(dimX), (long)(dimY)); - + /*saving V into V_old*/ copyIm(V1, V1_old, (long)(dimX), (long)(dimY), 1l); copyIm(V2, V2_old, (long)(dimX), (long)(dimY), 1l); - + /* upd V*/ UpdV_2D(V1, V2, P1, P2, Q1, Q2, Q3, (long)(dimX), (long)(dimY), tau); - + /*get new V*/ newU(V1, V1_old, (long)(dimX), (long)(dimY)); newU(V2, V2_old, (long)(dimX), (long)(dimY)); + + /* check early stopping criteria */ + if ((epsil != 0.0f) && (ll % 5 == 0)) { + re = 0.0f; re1 = 0.0f; + for(j=0; j<DimTotal; j++) + { + re += powf(U[j] - U_old[j],2); + re1 += powf(U[j],2); + } + re = sqrtf(re)/sqrtf(re1); + if (re < epsil) count++; + if (count > 3) break; + } } /*end of iterations*/ } else { /*3D case*/ float *P3, *Q4, *Q5, *Q6, *V3, *V3_old; - + P3 = calloc(DimTotal, sizeof(float)); Q4 = calloc(DimTotal, sizeof(float)); Q5 = calloc(DimTotal, sizeof(float)); Q6 = calloc(DimTotal, sizeof(float)); V3 = calloc(DimTotal, sizeof(float)); V3_old = calloc(DimTotal, sizeof(float)); - + /* Primal-dual iterations begin here */ for(ll = 0; ll < iter; ll++) { - + /* Calculate Dual Variable P */ DualP_3D(U, V1, V2, V3, P1, P2, P3, (long)(dimX), (long)(dimY), (long)(dimZ), sigma); - + /*Projection onto convex set for P*/ ProjP_3D(P1, P2, P3, (long)(dimX), (long)(dimY), (long)(dimZ), alpha1); - + /* Calculate Dual Variable Q */ DualQ_3D(V1, V2, V3, Q1, Q2, Q3, Q4, Q5, Q6, (long)(dimX), (long)(dimY), (long)(dimZ), sigma); - + /*Projection onto convex set for Q*/ ProjQ_3D(Q1, Q2, Q3, Q4, Q5, Q6, (long)(dimX), (long)(dimY), (long)(dimZ), alpha0); - + /*saving U into U_old*/ copyIm(U, U_old, (long)(dimX), (long)(dimY), (long)(dimZ)); - + /*adjoint operation -> divergence and projection of P*/ DivProjP_3D(U, U0, P1, P2, P3, (long)(dimX), (long)(dimY), (long)(dimZ), lambda, tau); - + /*get updated solution U*/ newU3D(U, U_old, (long)(dimX), (long)(dimY), (long)(dimZ)); - + /*saving V into V_old*/ copyIm_3Ar(V1, V2, V3, V1_old, V2_old, V3_old, (long)(dimX), (long)(dimY), (long)(dimZ)); - + /* upd V*/ UpdV_3D(V1, V2, V3, P1, P2, P3, Q1, Q2, Q3, Q4, Q5, Q6, (long)(dimX), (long)(dimY), (long)(dimZ), tau); - + /*get new V*/ newU3D_3Ar(V1, V2, V3, V1_old, V2_old, V3_old, (long)(dimX), (long)(dimY), (long)(dimZ)); + + /* check early stopping criteria */ + if ((epsil != 0.0f) && (ll % 5 == 0)) { + re = 0.0f; re1 = 0.0f; + for(j=0; j<DimTotal; j++) + { + re += powf(U[j] - U_old[j],2); + re1 += powf(U[j],2); + } + re = sqrtf(re)/sqrtf(re1); + if (re < epsil) count++; + if (count > 3) break; + } + } /*end of iterations*/ free(P3);free(Q4);free(Q5);free(Q6);free(V3);free(V3_old); } - + /*freeing*/ free(P1);free(P2);free(Q1);free(Q2);free(Q3);free(U_old); free(V1);free(V2);free(V1_old);free(V2_old); - return *U; + + /*adding info into info_vector */ + infovector[0] = (float)(ll); /*iterations number (if stopped earlier based on tolerance)*/ + infovector[1] = re; /* reached tolerance */ + + return 0; } /********************************************************************/ @@ -172,7 +209,7 @@ float DualP_2D(float *U, float *V1, float *V2, float *P1, float *P2, long dimX, else P1[index] += sigma*((U[j*dimX+(i+1)] - U[index]) - V1[index]); if (j == dimY-1) P2[index] += sigma*(-V2[index]); else P2[index] += sigma*((U[(j+1)*dimX+i] - U[index]) - V2[index]); - + }} return 1; } @@ -245,15 +282,15 @@ float DivProjP_2D(float *U, float *U0, float *P1, float *P2, long dimX, long dim for(i=0; i<dimX; i++) { for(j=0; j<dimY; j++) { index = j*dimX+i; - + if (i == 0) P_v1 = P1[index]; else if (i == dimX-1) P_v1 = -P1[j*dimX+(i-1)]; else P_v1 = P1[index] - P1[j*dimX+(i-1)]; - + if (j == 0) P_v2 = P2[index]; else if (j == dimY-1) P_v2 = -P2[(j-1)*dimX+i]; else P_v2 = P2[index] - P2[(j-1)*dimX+i]; - + div = P_v1 + P_v2; U[index] = (lambda*(U[index] + tau*div) + tau*U0[index])/(lambda + tau); }} @@ -276,7 +313,7 @@ float UpdV_2D(float *V1, float *V2, float *P1, float *P2, float *Q1, float *Q2, for(i=0; i<dimX; i++) { for(j=0; j<dimY; j++) { index = j*dimX+i; - + /* boundary conditions (Neuman) */ if (i == 0) { q1 = Q1[index]; @@ -287,7 +324,7 @@ float UpdV_2D(float *V1, float *V2, float *P1, float *P2, float *Q1, float *Q2, else { q1 = Q1[index] - Q1[j*dimX+(i-1)]; q3_x = Q3[index] - Q3[j*dimX+(i-1)]; } - + if (j == 0) { q2 = Q2[index]; q3_y = Q3[index]; } @@ -297,8 +334,8 @@ float UpdV_2D(float *V1, float *V2, float *P1, float *P2, float *Q1, float *Q2, else { q2 = Q2[index] - Q2[(j-1)*dimX+i]; q3_y = Q3[index] - Q3[(j-1)*dimX+i]; } - - + + div1 = q1 + q3_y; div2 = q3_x + q2; V1[index] += tau*(P1[index] + div1); @@ -375,7 +412,7 @@ float DualQ_3D(float *V1, float *V2, float *V3, float *Q1, float *Q2, float *Q3, q44 = V1[(dimX*dimY)*(k+1) + j*dimX+i] - V1[index]; q66 = V2[(dimX*dimY)*(k+1) + j*dimX+i] - V2[index]; } - + Q1[index] += sigma*(q1); /*Q11*/ Q2[index] += sigma*(q2); /*Q22*/ Q3[index] += sigma*(q3); /*Q33*/ @@ -417,7 +454,7 @@ float DivProjP_3D(float *U, float *U0, float *P1, float *P2, float *P3, long dim for(j=0; j<dimY; j++) { for(k=0; k<dimZ; k++) { index = (dimX*dimY)*k + j*dimX+i; - + if (i == 0) P_v1 = P1[index]; else if (i == dimX-1) P_v1 = -P1[(dimX*dimY)*k + j*dimX+(i-1)]; else P_v1 = P1[index] - P1[(dimX*dimY)*k + j*dimX+(i-1)]; @@ -427,7 +464,7 @@ float DivProjP_3D(float *U, float *U0, float *P1, float *P2, float *P3, long dim if (k == 0) P_v3 = P3[index]; else if (k == dimZ-1) P_v3 = -P3[(dimX*dimY)*(k-1) + (j)*dimX+i]; else P_v3 = P3[index] - P3[(dimX*dimY)*(k-1) + (j)*dimX+i]; - + div = P_v1 + P_v2 + P_v3; U[index] = (lambda*(U[index] + tau*div) + tau*U0[index])/(lambda + tau); }}} @@ -446,7 +483,7 @@ float UpdV_3D(float *V1, float *V2, float *V3, float *P1, float *P2, float *P3, q1 = 0.0f; q4x= 0.0f; q5x= 0.0f; q2= 0.0f; q4y= 0.0f; q6y= 0.0f; q6z= 0.0f; q5z= 0.0f; q3= 0.0f; /* Q1 - Q11, Q2 - Q22, Q3 - Q33, Q4 - Q21/Q12, Q5 - Q31/Q13, Q6 - Q32/Q23*/ /* symmetric boundary conditions (Neuman) */ - + if (i == 0) { q1 = Q1[index]; q4x = Q4[index]; @@ -483,11 +520,11 @@ float UpdV_3D(float *V1, float *V2, float *V3, float *P1, float *P2, float *P3, q6z = Q6[index] - Q6[(dimX*dimY)*(k-1) + (j)*dimX+i]; q5z = Q5[index] - Q5[(dimX*dimY)*(k-1) + (j)*dimX+i]; q3 = Q3[index] - Q3[(dimX*dimY)*(k-1) + (j)*dimX+i]; } - + div1 = q1 + q4y + q5z; div2 = q4x + q2 + q6z; div3 = q5x + q6y + q3; - + V1[index] += tau*(P1[index] + div1); V2[index] += tau*(P2[index] + div2); V3[index] += tau*(P3[index] + div3); @@ -529,4 +566,3 @@ float newU3D_3Ar(float *V1, float *V2, float *V3, float *V1_old, float *V2_old, } return 1; } - diff --git a/src/Core/regularisers_CPU/TGV_core.h b/src/Core/regularisers_CPU/TGV_core.h index 11b12c1..652d59f 100644 --- a/src/Core/regularisers_CPU/TGV_core.h +++ b/src/Core/regularisers_CPU/TGV_core.h @@ -25,7 +25,7 @@ limitations under the License. #include "utils.h" #include "CCPiDefines.h" -/* C-OMP implementation of Primal-Dual denoising method for +/* C-OMP implementation of Primal-Dual denoising method for * Total Generilized Variation (TGV)-L2 model [1] (2D/3D) * * Input Parameters: @@ -35,20 +35,22 @@ limitations under the License. * 4. parameter to control the second-order term (alpha0) * 5. Number of Chambolle-Pock (Primal-Dual) iterations * 6. Lipshitz constant (default is 12) - * + * 7. eplsilon: tolerance constant + * * Output: - * Filtered/regularised image/volume + * [1] Filtered/regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * References: * [1] K. Bredies "Total Generalized Variation" */ - - + + #ifdef __cplusplus extern "C" { #endif -CCPI_EXPORT float TGV_main(float *U0, float *U, float lambda, float alpha1, float alpha0, int iter, float L2, int dimX, int dimY, int dimZ); +CCPI_EXPORT float TGV_main(float *U0, float *U, float *infovector, float lambda, float alpha1, float alpha0, int iter, float L2, float epsil, int dimX, int dimY, int dimZ); /* 2D functions */ CCPI_EXPORT float DualP_2D(float *U, float *V1, float *V2, float *P1, float *P2, long dimX, long dimY, float sigma); diff --git a/src/Core/regularisers_GPU/Diffus_4thO_GPU_core.cu b/src/Core/regularisers_GPU/Diffus_4thO_GPU_core.cu index a4dbe70..afd2026 100644 --- a/src/Core/regularisers_GPU/Diffus_4thO_GPU_core.cu +++ b/src/Core/regularisers_GPU/Diffus_4thO_GPU_core.cu @@ -15,23 +15,28 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -*/ +*/ #include "Diffus_4thO_GPU_core.h" #include "shared.h" +#include <thrust/functional.h> +#include <thrust/device_vector.h> +#include <thrust/transform_reduce.h> /* CUDA implementation of fourth-order diffusion scheme [1] for piecewise-smooth recovery (2D/3D case) - * The minimisation is performed using explicit scheme. + * The minimisation is performed using explicit scheme. * * Input Parameters: - * 1. Noisy image/volume + * 1. Noisy image/volume * 2. lambda - regularization parameter * 3. Edge-preserving parameter (sigma) - * 4. Number of iterations, for explicit scheme >= 150 is recommended + * 4. Number of iterations, for explicit scheme >= 150 is recommended * 5. tau - time-marching step for explicit scheme + * 6. eplsilon: tolerance constant * * Output: - * [1] Regularized image/volume + * [1] Filtered/regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the paper by * [1] Hajiaboli, M.R., 2011. An anisotropic fourth-order diffusion filter for image noise removal. International Journal of Computer Vision, 92(2), pp.177-191. @@ -40,7 +45,7 @@ limitations under the License. #define BLKXSIZE 8 #define BLKYSIZE 8 #define BLKZSIZE 8 - + #define BLKXSIZE2D 16 #define BLKYSIZE2D 16 #define EPS 1.0e-7 @@ -52,14 +57,14 @@ __global__ void Weighted_Laplc2D_kernel(float *W_Lapl, float *U0, float sigma, i { int i1,i2,j1,j2; float gradX, gradX_sq, gradY, gradY_sq, gradXX, gradYY, gradXY, xy_2, denom, V_norm, V_orth, c, c_sq; - - int i = blockDim.x * blockIdx.x + threadIdx.x; + + int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; - + int index = i + dimX*j; - + if ((i >= 0) && (i < dimX) && (j >= 0) && (j < dimY)) { - + /* boundary conditions (Neumann reflections) */ i1 = i+1; if (i1 == dimX) i1 = i-1; i2 = i-1; if (i2 < 0) i2 = i+1; @@ -68,34 +73,34 @@ __global__ void Weighted_Laplc2D_kernel(float *W_Lapl, float *U0, float sigma, i gradX = 0.5f*(U0[j*dimX+i2] - U0[j*dimX+i1]); gradX_sq = powf(gradX,2); - + gradY = 0.5f*(U0[j2*dimX+i] - U0[j1*dimX+i]); gradY_sq = powf(gradY,2); - + gradXX = U0[j*dimX+i2] + U0[j*dimX+i1] - 2*U0[index]; gradYY = U0[j2*dimX+i] + U0[j1*dimX+i] - 2*U0[index]; - + gradXY = 0.25f*(U0[j2*dimX+i2] + U0[j1*dimX+i1] - U0[j1*dimX+i2] - U0[j2*dimX+i1]); xy_2 = 2.0f*gradX*gradY*gradXY; - + denom = gradX_sq + gradY_sq; - + if (denom <= EPS) { V_norm = (gradXX*gradX_sq + xy_2 + gradYY*gradY_sq)/EPS; - V_orth = (gradXX*gradY_sq - xy_2 + gradYY*gradX_sq)/EPS; + V_orth = (gradXX*gradY_sq - xy_2 + gradYY*gradX_sq)/EPS; } else { V_norm = (gradXX*gradX_sq + xy_2 + gradYY*gradY_sq)/denom; - V_orth = (gradXX*gradY_sq - xy_2 + gradYY*gradX_sq)/denom; + V_orth = (gradXX*gradY_sq - xy_2 + gradYY*gradX_sq)/denom; } c = 1.0f/(1.0f + denom/sigma); c_sq = c*c; - + W_Lapl[index] = c_sq*V_norm + c*V_orth; } return; -} +} __global__ void Diffusion_update_step2D_kernel(float *Output, float *Input, float *W_Lapl, float lambdaPar, float sigmaPar2, float tau, int dimX, int dimY) { @@ -104,24 +109,24 @@ __global__ void Diffusion_update_step2D_kernel(float *Output, float *Input, floa int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; - + int index = i + dimX*j; - + if ((i >= 0) && (i < dimX) && (j >= 0) && (j < dimY)) { - + /* boundary conditions (Neumann reflections) */ i1 = i+1; if (i1 == dimX) i1 = i-1; i2 = i-1; if (i2 < 0) i2 = i+1; j1 = j+1; if (j1 == dimY) j1 = j-1; j2 = j-1; if (j2 < 0) j2 = j+1; - + gradXXc = W_Lapl[j*dimX+i2] + W_Lapl[j*dimX+i1] - 2*W_Lapl[index]; gradYYc = W_Lapl[j2*dimX+i] + W_Lapl[j1*dimX+i] - 2*W_Lapl[index]; Output[index] += tau*(-lambdaPar*(gradXXc + gradYYc) - (Output[index] - Input[index])); } return; -} +} /********************************************************************/ /***************************3D Functions*****************************/ /********************************************************************/ @@ -129,13 +134,13 @@ __global__ void Weighted_Laplc3D_kernel(float *W_Lapl, float *U0, float sigma, i { int i1,i2,j1,j2,k1,k2; float gradX, gradX_sq, gradY, gradY_sq, gradXX, gradYY, gradXY, xy_2, denom, V_norm, V_orth, c, c_sq, gradZ, gradZ_sq, gradZZ, gradXZ, gradYZ, xyz_1, xyz_2; - + int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + if ((i >= 0) && (i < dimX) && (j >= 0) && (j < dimY) && (k >= 0) && (k < dimZ)) { - + /* boundary conditions (Neumann reflections) */ i1 = i+1; if (i1 == dimX) i1 = i-1; i2 = i-1; if (i2 < 0) i2 = i+1; @@ -143,32 +148,32 @@ __global__ void Weighted_Laplc3D_kernel(float *W_Lapl, float *U0, float sigma, i j2 = j-1; if (j2 < 0) j2 = j+1; k1 = k+1; if (k1 == dimZ) k1 = k-1; k2 = k-1; if (k2 < 0) k2 = k+1; - + int index = (dimX*dimY)*k + j*dimX+i; - + gradX = 0.5f*(U0[(dimX*dimY)*k + j*dimX+i2] - U0[(dimX*dimY)*k + j*dimX+i1]); gradX_sq = pow(gradX,2); - + gradY = 0.5f*(U0[(dimX*dimY)*k + j2*dimX+i] - U0[(dimX*dimY)*k + j1*dimX+i]); gradY_sq = pow(gradY,2); - + gradZ = 0.5f*(U0[(dimX*dimY)*k2 + j*dimX+i] - U0[(dimX*dimY)*k1 + j*dimX+i]); gradZ_sq = pow(gradZ,2); - + gradXX = U0[(dimX*dimY)*k + j*dimX+i2] + U0[(dimX*dimY)*k + j*dimX+i1] - 2*U0[index]; gradYY = U0[(dimX*dimY)*k + j2*dimX+i] + U0[(dimX*dimY)*k + j1*dimX+i] - 2*U0[index]; gradZZ = U0[(dimX*dimY)*k2 + j*dimX+i] + U0[(dimX*dimY)*k1 + j*dimX+i] - 2*U0[index]; - + gradXY = 0.25f*(U0[(dimX*dimY)*k + j2*dimX+i2] + U0[(dimX*dimY)*k + j1*dimX+i1] - U0[(dimX*dimY)*k + j1*dimX+i2] - U0[(dimX*dimY)*k + j2*dimX+i1]); gradXZ = 0.25f*(U0[(dimX*dimY)*k2 + j*dimX+i2] - U0[(dimX*dimY)*k2+j*dimX+i1] - U0[(dimX*dimY)*k1+j*dimX+i2] + U0[(dimX*dimY)*k1+j*dimX+i1]); gradYZ = 0.25f*(U0[(dimX*dimY)*k2 +j2*dimX+i] - U0[(dimX*dimY)*k2+j1*dimX+i] - U0[(dimX*dimY)*k1+j2*dimX+i] + U0[(dimX*dimY)*k1+j1*dimX+i]); - + xy_2 = 2.0f*gradX*gradY*gradXY; xyz_1 = 2.0f*gradX*gradZ*gradXZ; xyz_2 = 2.0f*gradY*gradZ*gradYZ; - + denom = gradX_sq + gradY_sq + gradZ_sq; - + if (denom <= EPS) { V_norm = (gradXX*gradX_sq + gradYY*gradY_sq + gradZZ*gradZ_sq + xy_2 + xyz_1 + xyz_2)/EPS; V_orth = ((gradY_sq + gradZ_sq)*gradXX + (gradX_sq + gradZ_sq)*gradYY + (gradX_sq + gradY_sq)*gradZZ - xy_2 - xyz_1 - xyz_2)/EPS; @@ -180,7 +185,7 @@ __global__ void Weighted_Laplc3D_kernel(float *W_Lapl, float *U0, float sigma, i c = 1.0f/(1.0f + denom/sigma); c_sq = c*c; - + W_Lapl[index] = c_sq*V_norm + c*V_orth; } return; @@ -193,9 +198,9 @@ __global__ void Diffusion_update_step3D_kernel(float *Output, float *Input, floa int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + if ((i >= 0) && (i < dimX) && (j >= 0) && (j < dimY) && (k >= 0) && (k < dimZ)) { - + /* boundary conditions (Neumann reflections) */ i1 = i+1; if (i1 == dimX) i1 = i-1; i2 = i-1; if (i2 < 0) i2 = i+1; @@ -203,66 +208,160 @@ __global__ void Diffusion_update_step3D_kernel(float *Output, float *Input, floa j2 = j-1; if (j2 < 0) j2 = j+1; k1 = k+1; if (k1 == dimZ) k1 = k-1; k2 = k-1; if (k2 < 0) k2 = k+1; - + int index = (dimX*dimY)*k + j*dimX+i; - + gradXXc = W_Lapl[(dimX*dimY)*k + j*dimX+i2] + W_Lapl[(dimX*dimY)*k + j*dimX+i1] - 2*W_Lapl[index]; gradYYc = W_Lapl[(dimX*dimY)*k + j2*dimX+i] + W_Lapl[(dimX*dimY)*k + j1*dimX+i] - 2*W_Lapl[index]; gradZZc = W_Lapl[(dimX*dimY)*k2 + j*dimX+i] + W_Lapl[(dimX*dimY)*k1 + j*dimX+i] - 2*W_Lapl[index]; - + Output[index] += tau*(-lambdaPar*(gradXXc + gradYYc + gradZZc) - (Output[index] - Input[index])); } return; } + +__global__ void Diff4thcopy_kernel2D(float *Input, float* Output, int N, int M, int num_total) +{ + int xIndex = blockDim.x * blockIdx.x + threadIdx.x; + int yIndex = blockDim.y * blockIdx.y + threadIdx.y; + + int index = xIndex + N*yIndex; + + if (index < num_total) { + Output[index] = Input[index]; + } +} + + +__global__ void Diff4thResidCalc2D_kernel(float *Input1, float *Input2, float* Output, int N, int M, int num_total) +{ + int xIndex = blockDim.x * blockIdx.x + threadIdx.x; + int yIndex = blockDim.y * blockIdx.y + threadIdx.y; + + int index = xIndex + N*yIndex; + + if (index < num_total) { + Output[index] = Input1[index] - Input2[index]; + } +} + +__global__ void Diff4thcopy_kernel3D(float *Input, float* Output, int N, int M, int Z, int num_total) +{ + int i = blockDim.x * blockIdx.x + threadIdx.x; + int j = blockDim.y * blockIdx.y + threadIdx.y; + int k = blockDim.z * blockIdx.z + threadIdx.z; + + int index = (N*M)*k + i + N*j; + + if (index < num_total) { + Output[index] = Input[index]; + } +} + +__global__ void Diff4thResidCalc3D_kernel(float *Input1, float *Input2, float* Output, int N, int M, int Z, int num_total) +{ + int i = blockDim.x * blockIdx.x + threadIdx.x; + int j = blockDim.y * blockIdx.y + threadIdx.y; + int k = blockDim.z * blockIdx.z + threadIdx.z; + + int index = (N*M)*k + i + N*j; + + if (index < num_total) { + Output[index] = Input1[index] - Input2[index]; + } +} + /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /********************* MAIN HOST FUNCTION ******************/ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ -extern "C" int Diffus4th_GPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int N, int M, int Z) +extern "C" int Diffus4th_GPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, float epsil, int N, int M, int Z) { - int dimTotal, dev = 0; - CHECK(cudaSetDevice(dev)); - float *d_input, *d_output, *d_W_Lapl; + + int deviceCount = -1; // number of devices + cudaGetDeviceCount(&deviceCount); + if (deviceCount == 0) { + fprintf(stderr, "No CUDA devices found\n"); + return -1; + } + + int dimTotal, n, count = 0; + float *d_input, *d_output, *d_W_Lapl, *d_update_prev=NULL, re; + re = 0.0f; float sigmaPar2; sigmaPar2 = sigmaPar*sigmaPar; dimTotal = N*M*Z; - + CHECK(cudaMalloc((void**)&d_input,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&d_output,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&d_W_Lapl,dimTotal*sizeof(float))); - + if (epsil != 0.0f) checkCudaErrors( cudaMalloc((void**)&d_update_prev,dimTotal*sizeof(float)) ); + CHECK(cudaMemcpy(d_input,Input,dimTotal*sizeof(float),cudaMemcpyHostToDevice)); CHECK(cudaMemcpy(d_output,Input,dimTotal*sizeof(float),cudaMemcpyHostToDevice)); - - if (Z == 1) { - /*2D case */ - dim3 dimBlock(BLKXSIZE2D,BLKYSIZE2D); - dim3 dimGrid(idivup(N,BLKXSIZE2D), idivup(M,BLKYSIZE2D)); - - for(int n=0; n < iterationsNumb; n++) { - /* Calculating weighted Laplacian */ - Weighted_Laplc2D_kernel<<<dimGrid,dimBlock>>>(d_W_Lapl, d_output, sigmaPar2, N, M); - CHECK(cudaDeviceSynchronize()); - /* Perform iteration step */ - Diffusion_update_step2D_kernel<<<dimGrid,dimBlock>>>(d_output, d_input, d_W_Lapl, lambdaPar, sigmaPar2, tau, N, M); - CHECK(cudaDeviceSynchronize()); - } - } - else { - /*3D case*/ - dim3 dimBlock(BLKXSIZE,BLKYSIZE,BLKZSIZE); - dim3 dimGrid(idivup(N,BLKXSIZE), idivup(M,BLKYSIZE),idivup(Z,BLKZSIZE)); - for(int n=0; n < iterationsNumb; n++) { - /* Calculating weighted Laplacian */ - Weighted_Laplc3D_kernel<<<dimGrid,dimBlock>>>(d_W_Lapl, d_output, sigmaPar2, N, M, Z); - CHECK(cudaDeviceSynchronize()); - /* Perform iteration step */ - Diffusion_update_step3D_kernel<<<dimGrid,dimBlock>>>(d_output, d_input, d_W_Lapl, lambdaPar, sigmaPar2, tau, N, M, Z); - CHECK(cudaDeviceSynchronize()); - } - } + + /*2D case */ + dim3 dimBlock(BLKXSIZE2D,BLKYSIZE2D); + dim3 dimGrid(idivup(N,BLKXSIZE2D), idivup(M,BLKYSIZE2D)); + dim3 dimBlock3(BLKXSIZE,BLKYSIZE,BLKZSIZE); + dim3 dimGrid3(idivup(N,BLKXSIZE), idivup(M,BLKYSIZE),idivup(Z,BLKZSIZE)); + + + for(n=0; n < iterationsNumb; n++) { + + if ((epsil != 0.0f) && (n % 5 == 0)) { + if (Z == 1) Diff4thcopy_kernel2D<<<dimGrid,dimBlock>>>(d_output, d_update_prev, N, M, dimTotal); + else Diff4thcopy_kernel3D<<<dimGrid3,dimBlock3>>>(d_output, d_update_prev, N, M, Z, dimTotal); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + } + + if (Z == 1) { + /*2D case */ + /* Calculating weighted Laplacian */ + Weighted_Laplc2D_kernel<<<dimGrid,dimBlock>>>(d_W_Lapl, d_output, sigmaPar2, N, M); + CHECK(cudaDeviceSynchronize()); + /* Perform iteration step */ + Diffusion_update_step2D_kernel<<<dimGrid,dimBlock>>>(d_output, d_input, d_W_Lapl, lambdaPar, sigmaPar2, tau, N, M); + CHECK(cudaDeviceSynchronize()); + } + else { + /* Calculating weighted Laplacian */ + Weighted_Laplc3D_kernel<<<dimGrid3,dimBlock3>>>(d_W_Lapl, d_output, sigmaPar2, N, M, Z); + CHECK(cudaDeviceSynchronize()); + /* Perform iteration step */ + Diffusion_update_step3D_kernel<<<dimGrid3,dimBlock3>>>(d_output, d_input, d_W_Lapl, lambdaPar, sigmaPar2, tau, N, M, Z); + CHECK(cudaDeviceSynchronize()); + } + if ((epsil != 0.0f) && (n % 5 == 0)) { + /* calculate norm - stopping rules using the Thrust library */ + if (Z == 1) Diff4thResidCalc2D_kernel<<<dimGrid,dimBlock>>>(d_output, d_update_prev, d_W_Lapl, N, M, dimTotal); + else Diff4thResidCalc3D_kernel<<<dimGrid3,dimBlock3>>>(d_output, d_update_prev, d_W_Lapl, N, M, Z, dimTotal); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors( cudaPeekAtLastError() ); + + // setup arguments + square<float> unary_op; + thrust::plus<float> binary_op; + thrust::device_vector<float> d_vec(d_W_Lapl, d_W_Lapl + dimTotal); + float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); + thrust::device_vector<float> d_vec2(d_output, d_output + dimTotal); + float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); + + // compute norm + re = (reduction/reduction2); + if (re < epsil) count++; + if (count > 3) break; + } + } + CHECK(cudaMemcpy(Output,d_output,dimTotal*sizeof(float),cudaMemcpyDeviceToHost)); CHECK(cudaFree(d_input)); CHECK(cudaFree(d_output)); CHECK(cudaFree(d_W_Lapl)); + if (epsil != 0.0f) cudaFree(d_update_prev); + + /*adding info into info_vector */ + infovector[0] = (float)(n); /*iterations number (if stopped earlier based on tolerance)*/ + infovector[1] = re; /* reached tolerance */ return 0; } diff --git a/src/Core/regularisers_GPU/Diffus_4thO_GPU_core.h b/src/Core/regularisers_GPU/Diffus_4thO_GPU_core.h index 77d5d79..709bb20 100644 --- a/src/Core/regularisers_GPU/Diffus_4thO_GPU_core.h +++ b/src/Core/regularisers_GPU/Diffus_4thO_GPU_core.h @@ -3,6 +3,6 @@ #include "CCPiDefines.h" #include <stdio.h> -extern "C" CCPI_EXPORT int Diffus4th_GPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int N, int M, int Z); +extern "C" CCPI_EXPORT int Diffus4th_GPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, float epsil, int N, int M, int Z); -#endif +#endif diff --git a/src/Core/regularisers_GPU/LLT_ROF_GPU_core.cu b/src/Core/regularisers_GPU/LLT_ROF_GPU_core.cu index 64f04d5..3c578f3 100644 --- a/src/Core/regularisers_GPU/LLT_ROF_GPU_core.cu +++ b/src/Core/regularisers_GPU/LLT_ROF_GPU_core.cu @@ -486,17 +486,25 @@ extern "C" int LLT_ROF_GPU_main(float *Input, float *Output, float *infovector, dim3 dimGrid(idivup(N,BLKXSIZE2D), idivup(M,BLKYSIZE2D)); for(n=0; n < iterationsNumb; n++) { + + + if ((epsil != 0.0f) && (n % 5 == 0)) { + ROFLLTcopy_kernel2D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, N, M, DimTotal); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + } + /****************ROF******************/ - /* calculate first-order differences */ + /* calculate first-order differences */ D1_func2D_ROF_kernel<<<dimGrid,dimBlock>>>(d_update, D1_ROF, N, M); CHECK(cudaDeviceSynchronize()); - D2_func2D_ROF_kernel<<<dimGrid,dimBlock>>>(d_update, D2_ROF, N, M); + D2_func2D_ROF_kernel<<<dimGrid,dimBlock>>>(d_update, D2_ROF, N, M); CHECK(cudaDeviceSynchronize()); /****************LLT******************/ - /* estimate second-order derrivatives */ - der2D_LLT_kernel<<<dimGrid,dimBlock>>>(d_update, D1_LLT, D2_LLT, N, M); - /* Joint update for ROF and LLT models */ - Update2D_LLT_ROF_kernel<<<dimGrid,dimBlock>>>(d_input, d_update, D1_LLT, D2_LLT, D1_ROF, D2_ROF, lambdaROF, lambdaLLT, tau, N, M); + /* estimate second-order derrivatives */ + der2D_LLT_kernel<<<dimGrid,dimBlock>>>(d_update, D1_LLT, D2_LLT, N, M); + /* Joint update for ROF and LLT models */ + Update2D_LLT_ROF_kernel<<<dimGrid,dimBlock>>>(d_input, d_update, D1_LLT, D2_LLT, D1_ROF, D2_ROF, lambdaROF, lambdaLLT, tau, N, M); CHECK(cudaDeviceSynchronize()); if ((epsil != 0.0f) && (n % 5 == 0)) { @@ -517,10 +525,6 @@ extern "C" int LLT_ROF_GPU_main(float *Input, float *Output, float *infovector, re = (reduction/reduction2); if (re < epsil) count++; if (count > 3) break; - - ROFLLTcopy_kernel2D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, N, M, DimTotal); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); } } } @@ -535,19 +539,26 @@ extern "C" int LLT_ROF_GPU_main(float *Input, float *Output, float *infovector, CHECK(cudaMalloc((void**)&D3_ROF,DimTotal*sizeof(float))); for(n=0; n < iterationsNumb; n++) { + + if ((epsil != 0.0f) && (n % 5 == 0)) { + ROFLLTcopy_kernel3D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, N, M, Z, DimTotal); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + } + /****************ROF******************/ - /* calculate first-order differences */ + /* calculate first-order differences */ D1_func3D_ROF_kernel<<<dimGrid,dimBlock>>>(d_update, D1_ROF, N, M, Z); CHECK(cudaDeviceSynchronize()); - D2_func3D_ROF_kernel<<<dimGrid,dimBlock>>>(d_update, D2_ROF, N, M, Z); + D2_func3D_ROF_kernel<<<dimGrid,dimBlock>>>(d_update, D2_ROF, N, M, Z); CHECK(cudaDeviceSynchronize()); D3_func3D_ROF_kernel<<<dimGrid,dimBlock>>>(d_update, D3_ROF, N, M, Z); CHECK(cudaDeviceSynchronize()); /****************LLT******************/ /* estimate second-order derrivatives */ - der3D_LLT_kernel<<<dimGrid,dimBlock>>>(d_update, D1_LLT, D2_LLT, D3_LLT, N, M, Z); - /* Joint update for ROF and LLT models */ - Update3D_LLT_ROF_kernel<<<dimGrid,dimBlock>>>(d_input, d_update, D1_LLT, D2_LLT, D3_LLT, D1_ROF, D2_ROF, D3_ROF, lambdaROF, lambdaLLT, tau, N, M, Z); + der3D_LLT_kernel<<<dimGrid,dimBlock>>>(d_update, D1_LLT, D2_LLT, D3_LLT, N, M, Z); + /* Joint update for ROF and LLT models */ + Update3D_LLT_ROF_kernel<<<dimGrid,dimBlock>>>(d_input, d_update, D1_LLT, D2_LLT, D3_LLT, D1_ROF, D2_ROF, D3_ROF, lambdaROF, lambdaLLT, tau, N, M, Z); CHECK(cudaDeviceSynchronize()); @@ -569,10 +580,6 @@ extern "C" int LLT_ROF_GPU_main(float *Input, float *Output, float *infovector, re = (reduction/reduction2); if (re < epsil) count++; if (count > 3) break; - - ROFLLTcopy_kernel3D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, N, M, Z, DimTotal); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); } } diff --git a/src/Core/regularisers_GPU/NonlDiff_GPU_core.cu b/src/Core/regularisers_GPU/NonlDiff_GPU_core.cu index ff7ce4d..de9abd4 100644 --- a/src/Core/regularisers_GPU/NonlDiff_GPU_core.cu +++ b/src/Core/regularisers_GPU/NonlDiff_GPU_core.cu @@ -15,39 +15,43 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -*/ +*/ #include "NonlDiff_GPU_core.h" #include "shared.h" +#include <thrust/functional.h> +#include <thrust/device_vector.h> +#include <thrust/transform_reduce.h> /* CUDA implementation of linear and nonlinear diffusion with the regularisation model [1,2] (2D/3D case) - * The minimisation is performed using explicit scheme. + * The minimisation is performed using explicit scheme. * * Input Parameters: - * 1. Noisy image/volume + * 1. Noisy image/volume * 2. lambda - regularization parameter * 3. Edge-preserving parameter (sigma), when sigma equals to zero nonlinear diffusion -> linear diffusion - * 4. Number of iterations, for explicit scheme >= 150 is recommended + * 4. Number of iterations, for explicit scheme >= 150 is recommended * 5. tau - time-marching step for explicit scheme * 6. Penalty type: 1 - Huber, 2 - Perona-Malik, 3 - Tukey Biweight - * - * Output: - * [1] Regularized image/volume + * 7. eplsilon: tolerance constant + + * Output: + * [1] Filtered/regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the paper by * [1] Perona, P. and Malik, J., 1990. Scale-space and edge detection using anisotropic diffusion. IEEE Transactions on pattern analysis and machine intelligence, 12(7), pp.629-639. * [2] Black, M.J., Sapiro, G., Marimont, D.H. and Heeger, D., 1998. Robust anisotropic diffusion. IEEE Transactions on image processing, 7(3), pp.421-432. */ - #define BLKXSIZE 8 #define BLKYSIZE 8 #define BLKZSIZE 8 - + #define BLKXSIZE2D 16 #define BLKYSIZE2D 16 #define EPS 1.0e-5 - + #define idivup(a, b) ( ((a)%(b) != 0) ? (a)/(b)+1 : (a)/(b) ) #define MAX(x, y) (((x) > (y)) ? (x) : (y)) @@ -56,8 +60,8 @@ limitations under the License. __host__ __device__ int signNDF (float x) { return (x > 0) - (x < 0); -} - +} + /********************************************************************/ /***************************2D Functions*****************************/ /********************************************************************/ @@ -67,69 +71,69 @@ __global__ void LinearDiff2D_kernel(float *Input, float *Output, float lambdaPar float e,w,n,s,e1,w1,n1,s1; int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; - + int index = i + N*j; - + if ((i >= 0) && (i < N) && (j >= 0) && (j < M)) { - + /* boundary conditions (Neumann reflections) */ i1 = i+1; if (i1 == N) i1 = i-1; i2 = i-1; if (i2 < 0) i2 = i+1; j1 = j+1; if (j1 == M) j1 = j-1; j2 = j-1; if (j2 < 0) j2 = j+1; - + e = Output[j*N+i1]; w = Output[j*N+i2]; n = Output[j1*N+i]; s = Output[j2*N+i]; - + e1 = e - Output[index]; w1 = w - Output[index]; n1 = n - Output[index]; s1 = s - Output[index]; - - Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1) - (Output[index] - Input[index])); + + Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1) - (Output[index] - Input[index])); } - } - + } + __global__ void NonLinearDiff2D_kernel(float *Input, float *Output, float lambdaPar, float sigmaPar, float tau, int penaltytype, int N, int M) { int i1,i2,j1,j2; float e,w,n,s,e1,w1,n1,s1; int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; - + int index = i + N*j; - + if ((i >= 0) && (i < N) && (j >= 0) && (j < M)) { - + /* boundary conditions (Neumann reflections) */ i1 = i+1; if (i1 == N) i1 = i-1; i2 = i-1; if (i2 < 0) i2 = i+1; j1 = j+1; if (j1 == M) j1 = j-1; j2 = j-1; if (j2 < 0) j2 = j+1; - + e = Output[j*N+i1]; w = Output[j*N+i2]; n = Output[j1*N+i]; s = Output[j2*N+i]; - + e1 = e - Output[index]; w1 = w - Output[index]; n1 = n - Output[index]; s1 = s - Output[index]; - + if (penaltytype == 1){ /* Huber penalty */ if (abs(e1) > sigmaPar) e1 = signNDF(e1); else e1 = e1/sigmaPar; - + if (abs(w1) > sigmaPar) w1 = signNDF(w1); else w1 = w1/sigmaPar; - + if (abs(n1) > sigmaPar) n1 = signNDF(n1); else n1 = n1/sigmaPar; - + if (abs(s1) > sigmaPar) s1 = signNDF(s1); else s1 = s1/sigmaPar; } @@ -152,10 +156,10 @@ __global__ void LinearDiff2D_kernel(float *Input, float *Output, float lambdaPar else s1 = 0.0f; } else printf("%s \n", "No penalty function selected! Use 1,2 or 3."); - - Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1) - (Output[index] - Input[index])); + + Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1) - (Output[index] - Input[index])); } - } + } /********************************************************************/ /***************************3D Functions*****************************/ /********************************************************************/ @@ -167,11 +171,11 @@ __global__ void LinearDiff3D_kernel(float *Input, float *Output, float lambdaPar int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - - int index = (N*M)*k + i + N*j; - + + int index = (N*M)*k + i + N*j; + if ((i >= 0) && (i < N) && (j >= 0) && (j < M) && (k >= 0) && (k < Z)) { - + /* boundary conditions (Neumann reflections) */ i1 = i+1; if (i1 == N) i1 = i-1; i2 = i-1; if (i2 < 0) i2 = i+1; @@ -179,24 +183,24 @@ __global__ void LinearDiff3D_kernel(float *Input, float *Output, float lambdaPar j2 = j-1; if (j2 < 0) j2 = j+1; k1 = k+1; if (k1 == Z) k1 = k-1; k2 = k-1; if (k2 < 0) k2 = k+1; - + e = Output[(N*M)*k + i1 + N*j]; w = Output[(N*M)*k + i2 + N*j]; n = Output[(N*M)*k + i + N*j1]; s = Output[(N*M)*k + i + N*j2]; u = Output[(N*M)*k1 + i + N*j]; d = Output[(N*M)*k2 + i + N*j]; - + e1 = e - Output[index]; w1 = w - Output[index]; n1 = n - Output[index]; s1 = s - Output[index]; u1 = u - Output[index]; d1 = d - Output[index]; - - Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1 + u1 + d1) - (Output[index] - Input[index])); + + Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1 + u1 + d1) - (Output[index] - Input[index])); } - } + } __global__ void NonLinearDiff3D_kernel(float *Input, float *Output, float lambdaPar, float sigmaPar, float tau, int penaltytype, int N, int M, int Z) { @@ -205,11 +209,11 @@ __global__ void NonLinearDiff3D_kernel(float *Input, float *Output, float lambda int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - - int index = (N*M)*k + i + N*j; - + + int index = (N*M)*k + i + N*j; + if ((i >= 0) && (i < N) && (j >= 0) && (j < M) && (k >= 0) && (k < Z)) { - + /* boundary conditions (Neumann reflections) */ i1 = i+1; if (i1 == N) i1 = i-1; i2 = i-1; if (i2 < 0) i2 = i+1; @@ -217,41 +221,41 @@ __global__ void NonLinearDiff3D_kernel(float *Input, float *Output, float lambda j2 = j-1; if (j2 < 0) j2 = j+1; k1 = k+1; if (k1 == Z) k1 = k-1; k2 = k-1; if (k2 < 0) k2 = k+1; - + e = Output[(N*M)*k + i1 + N*j]; w = Output[(N*M)*k + i2 + N*j]; n = Output[(N*M)*k + i + N*j1]; s = Output[(N*M)*k + i + N*j2]; u = Output[(N*M)*k1 + i + N*j]; d = Output[(N*M)*k2 + i + N*j]; - + e1 = e - Output[index]; w1 = w - Output[index]; n1 = n - Output[index]; s1 = s - Output[index]; u1 = u - Output[index]; d1 = d - Output[index]; - - + + if (penaltytype == 1){ /* Huber penalty */ if (abs(e1) > sigmaPar) e1 = signNDF(e1); else e1 = e1/sigmaPar; - + if (abs(w1) > sigmaPar) w1 = signNDF(w1); else w1 = w1/sigmaPar; - + if (abs(n1) > sigmaPar) n1 = signNDF(n1); else n1 = n1/sigmaPar; - + if (abs(s1) > sigmaPar) s1 = signNDF(s1); else s1 = s1/sigmaPar; - + if (abs(u1) > sigmaPar) u1 = signNDF(u1); else u1 = u1/sigmaPar; - + if (abs(d1) > sigmaPar) d1 = signNDF(d1); - else d1 = d1/sigmaPar; + else d1 = d1/sigmaPar; } else if (penaltytype == 2) { /* Perona-Malik */ @@ -279,34 +283,100 @@ __global__ void NonLinearDiff3D_kernel(float *Input, float *Output, float lambda } else printf("%s \n", "No penalty function selected! Use 1,2 or 3."); - Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1 + u1 + d1) - (Output[index] - Input[index])); + Output[index] += tau*(lambdaPar*(e1 + w1 + n1 + s1 + u1 + d1) - (Output[index] - Input[index])); } - } + } + + __global__ void NDFcopy_kernel2D(float *Input, float* Output, int N, int M, int num_total) + { + int xIndex = blockDim.x * blockIdx.x + threadIdx.x; + int yIndex = blockDim.y * blockIdx.y + threadIdx.y; + + int index = xIndex + N*yIndex; + + if (index < num_total) { + Output[index] = Input[index]; + } + } + __global__ void NDFResidCalc2D_kernel(float *Input1, float *Input2, float* Output, int N, int M, int num_total) + { + int xIndex = blockDim.x * blockIdx.x + threadIdx.x; + int yIndex = blockDim.y * blockIdx.y + threadIdx.y; + + int index = xIndex + N*yIndex; + + if (index < num_total) { + Output[index] = Input1[index] - Input2[index]; + } + } + __global__ void NDFcopy_kernel3D(float *Input, float* Output, int N, int M, int Z, int num_total) + { + int i = blockDim.x * blockIdx.x + threadIdx.x; + int j = blockDim.y * blockIdx.y + threadIdx.y; + int k = blockDim.z * blockIdx.z + threadIdx.z; + + int index = (N*M)*k + i + N*j; + + if (index < num_total) { + Output[index] = Input[index]; + } + } + __global__ void NDFResidCalc3D_kernel(float *Input1, float *Input2, float* Output, int N, int M, int Z, int num_total) + { + int i = blockDim.x * blockIdx.x + threadIdx.x; + int j = blockDim.y * blockIdx.y + threadIdx.y; + int k = blockDim.z * blockIdx.z + threadIdx.z; + + int index = (N*M)*k + i + N*j; + + if (index < num_total) { + Output[index] = Input1[index] - Input2[index]; + } + } + ///////////////////////////////////////////////// // HOST FUNCTION -extern "C" int NonlDiff_GPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, int N, int M, int Z) +extern "C" int NonlDiff_GPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, float epsil, int N, int M, int Z) { - // set up device - int dev = 0; - CHECK(cudaSetDevice(dev)); - float *d_input, *d_output; - float sigmaPar2; + int deviceCount = -1; // number of devices + cudaGetDeviceCount(&deviceCount); + if (deviceCount == 0) { + fprintf(stderr, "No CUDA devices found\n"); + return -1; + } + int n, count, ImSize; + count = 0; + float *d_input, *d_output, *d_update_prev, *d_res; + float sigmaPar2, re = 0.0f; sigmaPar2 = sigmaPar/sqrt(2.0f); - - CHECK(cudaMalloc((void**)&d_input,N*M*Z*sizeof(float))); - CHECK(cudaMalloc((void**)&d_output,N*M*Z*sizeof(float))); - - CHECK(cudaMemcpy(d_input,Input,N*M*Z*sizeof(float),cudaMemcpyHostToDevice)); - CHECK(cudaMemcpy(d_output,Input,N*M*Z*sizeof(float),cudaMemcpyHostToDevice)); - + ImSize = N*M*Z; + + + CHECK(cudaMalloc((void**)&d_input,ImSize*sizeof(float))); + CHECK(cudaMalloc((void**)&d_output,ImSize*sizeof(float))); + if (epsil != 0.0f) { + checkCudaErrors( cudaMalloc((void**)&d_update_prev,ImSize*sizeof(float)) ); + checkCudaErrors( cudaMalloc((void**)&d_res,ImSize*sizeof(float)) ); + } + + CHECK(cudaMemcpy(d_input,Input,ImSize*sizeof(float),cudaMemcpyHostToDevice)); + CHECK(cudaMemcpy(d_output,Input,ImSize*sizeof(float),cudaMemcpyHostToDevice)); + if (Z == 1) { - /*2D case */ - + /*2D case */ + dim3 dimBlock(BLKXSIZE2D,BLKYSIZE2D); dim3 dimGrid(idivup(N,BLKXSIZE2D), idivup(M,BLKYSIZE2D)); - - for(int n=0; n < iterationsNumb; n++) { + + for(n=0; n < iterationsNumb; n++) { + + if ((epsil != 0.0f) && (n % 5 == 0)) { + NDFcopy_kernel2D<<<dimGrid,dimBlock>>>(d_output, d_update_prev, N, M, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + } + if (sigmaPar == 0.0f) { /* linear diffusion (heat equation) */ LinearDiff2D_kernel<<<dimGrid,dimBlock>>>(d_input, d_output, lambdaPar, tau, N, M); @@ -317,13 +387,40 @@ extern "C" int NonlDiff_GPU_main(float *Input, float *Output, float lambdaPar, f NonLinearDiff2D_kernel<<<dimGrid,dimBlock>>>(d_input, d_output, lambdaPar, sigmaPar2, tau, penaltytype, N, M); CHECK(cudaDeviceSynchronize()); } + + if ((epsil != 0.0f) && (n % 5 == 0)) { + /* calculate norm - stopping rules using the Thrust library */ + NDFResidCalc2D_kernel<<<dimGrid,dimBlock>>>(d_output, d_update_prev, d_res, N, M, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors( cudaPeekAtLastError() ); + + // setup arguments + square<float> unary_op; + thrust::plus<float> binary_op; + thrust::device_vector<float> d_vec(d_res, d_res + ImSize); + float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); + thrust::device_vector<float> d_vec2(d_output, d_output + ImSize); + float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); + + // compute norm + re = (reduction/reduction2); + if (re < epsil) count++; + if (count > 3) break; + } } } else { /*3D case*/ dim3 dimBlock(BLKXSIZE,BLKYSIZE,BLKZSIZE); dim3 dimGrid(idivup(N,BLKXSIZE), idivup(M,BLKYSIZE),idivup(Z,BLKZSIZE)); - for(int n=0; n < iterationsNumb; n++) { + for(n=0; n < iterationsNumb; n++) { + + if ((epsil != 0.0f) && (n % 5 == 0)) { + NDFcopy_kernel3D<<<dimGrid,dimBlock>>>(d_output, d_update_prev, N, M, Z, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + } + if (sigmaPar == 0.0f) { /* linear diffusion (heat equation) */ LinearDiff3D_kernel<<<dimGrid,dimBlock>>>(d_input, d_output, lambdaPar, tau, N, M, Z); @@ -334,12 +431,38 @@ extern "C" int NonlDiff_GPU_main(float *Input, float *Output, float lambdaPar, f NonLinearDiff3D_kernel<<<dimGrid,dimBlock>>>(d_input, d_output, lambdaPar, sigmaPar2, tau, penaltytype, N, M, Z); CHECK(cudaDeviceSynchronize()); } + + if ((epsil != 0.0f) && (n % 5 == 0)) { + /* calculate norm - stopping rules using the Thrust library */ + NDFResidCalc3D_kernel<<<dimGrid,dimBlock>>>(d_output, d_update_prev, d_res, N, M, Z, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors( cudaPeekAtLastError() ); + + // setup arguments + square<float> unary_op; + thrust::plus<float> binary_op; + thrust::device_vector<float> d_vec(d_res, d_res + ImSize); + float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); + thrust::device_vector<float> d_vec2(d_output, d_output + ImSize); + float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); + + // compute norm + re = (reduction/reduction2); + if (re < epsil) count++; + if (count > 3) break; + } } - - } - CHECK(cudaMemcpy(Output,d_output,N*M*Z*sizeof(float),cudaMemcpyDeviceToHost)); + + } + CHECK(cudaMemcpy(Output,d_output,ImSize*sizeof(float),cudaMemcpyDeviceToHost)); CHECK(cudaFree(d_input)); CHECK(cudaFree(d_output)); - //cudaDeviceReset(); + if (epsil != 0.0f) { + CHECK(cudaFree(d_update_prev)); + CHECK(cudaFree(d_res)); + } + + infovector[0] = (float)(n); /*iterations number (if stopped earlier based on tolerance)*/ + infovector[1] = re; /* reached tolerance */ return 0; } diff --git a/src/Core/regularisers_GPU/NonlDiff_GPU_core.h b/src/Core/regularisers_GPU/NonlDiff_GPU_core.h index 5fe457e..48852f8 100644 --- a/src/Core/regularisers_GPU/NonlDiff_GPU_core.h +++ b/src/Core/regularisers_GPU/NonlDiff_GPU_core.h @@ -3,6 +3,6 @@ #include "CCPiDefines.h" #include <stdio.h> -extern "C" CCPI_EXPORT int NonlDiff_GPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, int N, int M, int Z); +extern "C" CCPI_EXPORT int NonlDiff_GPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, float epsil, int N, int M, int Z); -#endif +#endif diff --git a/src/Core/regularisers_GPU/TGV_GPU_core.cu b/src/Core/regularisers_GPU/TGV_GPU_core.cu index 849219b..fc462fe 100644 --- a/src/Core/regularisers_GPU/TGV_GPU_core.cu +++ b/src/Core/regularisers_GPU/TGV_GPU_core.cu @@ -15,12 +15,16 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -*/ +*/ #include "TGV_GPU_core.h" #include "shared.h" +#include <thrust/functional.h> +#include <thrust/device_vector.h> +#include <thrust/transform_reduce.h> -/* CUDA implementation of Primal-Dual denoising method for + +/* CUDA implementation of Primal-Dual denoising method for * Total Generilized Variation (TGV)-L2 model [1] (2D/3D case) * * Input Parameters: @@ -30,15 +34,17 @@ limitations under the License. * 4. parameter to control the second-order term (alpha0) * 5. Number of Chambolle-Pock (Primal-Dual) iterations * 6. Lipshitz constant (default is 12) + * 7. eplsilon: tolerance constant * * Output: - * Filtered/regularised image - * + * [1] Filtered/regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] + * References: * [1] K. Bredies "Total Generalized Variation" */ - - + + #define BLKXSIZE2D 16 #define BLKYSIZE2D 16 @@ -52,34 +58,34 @@ limitations under the License. /***************************2D Functions*****************************/ /********************************************************************/ __global__ void DualP_2D_kernel(float *U, float *V1, float *V2, float *P1, float *P2, long dimX, long dimY, float sigma) -{ +{ const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - - long index = i + (dimX)*j; - + + long index = i + (dimX)*j; + if ((i < dimX) && (j < dimY)) { - /* symmetric boundary conditions (Neuman) */ - if ((i >= 0) && (i < dimX-1)) P1[index] += sigma*((U[(i+1) + dimX*j] - U[index]) - V1[index]); - else if (i == dimX-1) P1[index] -= sigma*(V1[index]); - else P1[index] = 0.0f; + /* symmetric boundary conditions (Neuman) */ + if ((i >= 0) && (i < dimX-1)) P1[index] += sigma*((U[(i+1) + dimX*j] - U[index]) - V1[index]); + else if (i == dimX-1) P1[index] -= sigma*(V1[index]); + else P1[index] = 0.0f; if ((j >= 0) && (j < dimY-1)) P2[index] += sigma*((U[i + dimX*(j+1)] - U[index]) - V2[index]); - else if (j == dimY-1) P2[index] -= sigma*(V2[index]); - else P2[index] = 0.0f; + else if (j == dimY-1) P2[index] -= sigma*(V2[index]); + else P2[index] = 0.0f; } return; -} +} __global__ void ProjP_2D_kernel(float *P1, float *P2, long dimX, long dimY, float alpha1) { float grad_magn; - + const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - - long index = i + (dimX)*j; - - if ((i < dimX) && (j < dimY)) { + + long index = i + (dimX)*j; + + if ((i < dimX) && (j < dimY)) { grad_magn = sqrtf(powf(P1[index],2) + powf(P2[index],2)); grad_magn = grad_magn/alpha1; if (grad_magn > 1.0f) { @@ -88,20 +94,20 @@ __global__ void ProjP_2D_kernel(float *P1, float *P2, long dimX, long dimY, floa } } return; -} +} __global__ void DualQ_2D_kernel(float *V1, float *V2, float *Q1, float *Q2, float *Q3, long dimX, long dimY, float sigma) { float q1, q2, q11, q22; const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - - long index = i + (dimX)*j; - - if ((i < dimX) && (j < dimY)) { + + long index = i + (dimX)*j; + + if ((i < dimX) && (j < dimY)) { q1 = 0.0f; q2 = 0.0f; q11 = 0.0f; q22 = 0.0f; - - if ((i >= 0) && (i < dimX-1)) { + + if ((i >= 0) && (i < dimX-1)) { /* boundary conditions (Neuman) */ q1 = V1[(i+1) + dimX*j] - V1[index]; q11 = V2[(i+1) + dimX*j] - V2[index]; @@ -110,23 +116,23 @@ __global__ void DualQ_2D_kernel(float *V1, float *V2, float *Q1, float *Q2, floa q2 = V2[i + dimX*(j+1)] - V2[index]; q22 = V1[i + dimX*(j+1)] - V1[index]; } - + Q1[index] += sigma*(q1); Q2[index] += sigma*(q2); Q3[index] += sigma*(0.5f*(q11 + q22)); - } + } return; -} +} __global__ void ProjQ_2D_kernel(float *Q1, float *Q2, float *Q3, long dimX, long dimY, float alpha0) { float grad_magn; const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - - long index = i + (dimX)*j; - - if ((i < dimX) && (j < dimY)) { + + long index = i + (dimX)*j; + + if ((i < dimX) && (j < dimY)) { grad_magn = sqrt(powf(Q1[index],2) + powf(Q2[index],2) + 2*powf(Q3[index],2)); grad_magn = grad_magn/alpha0; if (grad_magn > 1.0f) { @@ -136,18 +142,18 @@ __global__ void ProjQ_2D_kernel(float *Q1, float *Q2, float *Q3, long dimX, long } } return; -} +} __global__ void DivProjP_2D_kernel(float *U, float *U0, float *P1, float *P2, long dimX, long dimY, float lambda, float tau) { float P_v1, P_v2, div; const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - - long index = i + (dimX)*j; + + long index = i + (dimX)*j; if ((i < dimX) && (j < dimY)) { - + if ((i > 0) && (i < dimX-1)) P_v1 = P1[index] - P1[(i-1) + dimX*j]; else if (i == dimX-1) P_v1 = -P1[(i-1) + dimX*j]; else if (i == 0) P_v1 = P1[index]; @@ -158,48 +164,48 @@ __global__ void DivProjP_2D_kernel(float *U, float *U0, float *P1, float *P2, lo else if (j == 0) P_v2 = P2[index]; else P_v2 = 0.0f; - + div = P_v1 + P_v2; U[index] = (lambda*(U[index] + tau*div) + tau*U0[index])/(lambda + tau); } return; -} +} __global__ void UpdV_2D_kernel(float *V1, float *V2, float *P1, float *P2, float *Q1, float *Q2, float *Q3, long dimX, long dimY, float tau) { float q1, q3_x, q2, q3_y, div1, div2; long i1, j1; - + const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - - long index = i + (dimX)*j; - - if ((i < dimX) && (j < dimY)) { + + long index = i + (dimX)*j; + + if ((i < dimX) && (j < dimY)) { q1 = 0.0f; q3_x = 0.0f; q2 = 0.0f; q3_y = 0.0f; div1 = 0.0f; div2= 0.0f; - + i1 = (i-1) + dimX*j; j1 = (i) + dimX*(j-1); - /* boundary conditions (Neuman) */ + /* boundary conditions (Neuman) */ if ((i > 0) && (i < dimX-1)) { q1 = Q1[index] - Q1[i1]; - q3_x = Q3[index] - Q3[i1]; } + q3_x = Q3[index] - Q3[i1]; } else if (i == 0) { q1 = Q1[index]; - q3_x = Q3[index]; } + q3_x = Q3[index]; } else if (i == dimX-1) { q1 = -Q1[i1]; q3_x = -Q3[i1]; } else { q1 = 0.0f; q3_x = 0.0f; - } - + } + if ((j > 0) && (j < dimY-1)) { q2 = Q2[index] - Q2[j1]; - q3_y = Q3[index] - Q3[j1]; } + q3_y = Q3[index] - Q3[j1]; } else if (j == dimY-1) { q2 = -Q2[j1]; q3_y = -Q3[j1]; } @@ -209,23 +215,23 @@ __global__ void UpdV_2D_kernel(float *V1, float *V2, float *P1, float *P2, float else { q2 = 0.0f; q3_y = 0.0f; - } - + } + div1 = q1 + q3_y; div2 = q3_x + q2; V1[index] += tau*(P1[index] + div1); V2[index] += tau*(P2[index] + div2); } return; -} +} __global__ void copyIm_TGV_kernel(float *U, float *U_old, long dimX, long dimY) { const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - - long index = i + (dimX)*j; - + + long index = i + (dimX)*j; + if ((i < dimX) && (j < dimY)) { U_old[index] = U[index]; } @@ -235,9 +241,9 @@ __global__ void copyIm_TGV_kernel_ar2(float *V1, float *V2, float *V1_old, float { const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - - long index = i + (dimX)*j; - + + long index = i + (dimX)*j; + if ((i < dimX) && (j < dimY)) { V1_old[index] = V1[index]; V2_old[index] = V2[index]; @@ -248,9 +254,9 @@ __global__ void newU_kernel(float *U, float *U_old, long dimX, long dimY) { const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - - long index = i + (dimX)*j; - + + long index = i + (dimX)*j; + if ((i < dimX) && (j < dimY)) { U[index] = 2.0f*U[index] - U_old[index]; } @@ -261,12 +267,12 @@ __global__ void newU_kernel_ar2(float *V1, float *V2, float *V1_old, float *V2_o { const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - - long index = i + (dimX)*j; - + + long index = i + (dimX)*j; + if ((i < dimX) && (j < dimY)) { V1[index] = 2.0f*V1[index] - V1_old[index]; - V2[index] = 2.0f*V2[index] - V2_old[index]; + V2[index] = 2.0f*V2[index] - V2_old[index]; } } @@ -274,26 +280,26 @@ __global__ void newU_kernel_ar2(float *V1, float *V2, float *V1_old, float *V2_o /***************************3D Functions*****************************/ /********************************************************************/ __global__ void DualP_3D_kernel(float *U, float *V1, float *V2, float *V3, float *P1, float *P2, float *P3, long dimX, long dimY, long dimZ, float sigma) -{ +{ long index; const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; const long k = blockDim.z * blockIdx.z + threadIdx.z; - + index = (dimX*dimY)*k + i*dimX+j; - - if ((i < dimX) && (j < dimY) && (k < dimZ)) { - /* symmetric boundary conditions (Neuman) */ - if ((i >= 0) && (i < dimX-1)) P1[index] += sigma*((U[(dimX*dimY)*k + (i+1)*dimX+j] - U[index]) - V1[index]); - else if (i == dimX-1) P1[index] -= sigma*(V1[index]); + + if ((i < dimX) && (j < dimY) && (k < dimZ)) { + /* symmetric boundary conditions (Neuman) */ + if ((i >= 0) && (i < dimX-1)) P1[index] += sigma*((U[(dimX*dimY)*k + (i+1)*dimX+j] - U[index]) - V1[index]); + else if (i == dimX-1) P1[index] -= sigma*(V1[index]); else P1[index] = 0.0f; - if ((j >= 0) && (j < dimY-1)) P2[index] += sigma*((U[(dimX*dimY)*k + i*dimX+(j+1)] - U[index]) - V2[index]); - else if (j == dimY-1) P2[index] -= sigma*(V2[index]); - else P2[index] = 0.0f; - if ((k >= 0) && (k < dimZ-1)) P3[index] += sigma*((U[(dimX*dimY)*(k+1) + i*dimX+(j)] - U[index]) - V3[index]); - else if (k == dimZ-1) P3[index] -= sigma*(V3[index]); + if ((j >= 0) && (j < dimY-1)) P2[index] += sigma*((U[(dimX*dimY)*k + i*dimX+(j+1)] - U[index]) - V2[index]); + else if (j == dimY-1) P2[index] -= sigma*(V2[index]); + else P2[index] = 0.0f; + if ((k >= 0) && (k < dimZ-1)) P3[index] += sigma*((U[(dimX*dimY)*(k+1) + i*dimX+(j)] - U[index]) - V3[index]); + else if (k == dimZ-1) P3[index] -= sigma*(V3[index]); else P3[index] = 0.0f; - } + } return; } @@ -304,9 +310,9 @@ __global__ void ProjP_3D_kernel(float *P1, float *P2, float *P3, long dimX, long const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; const long k = blockDim.z * blockIdx.z + threadIdx.z; - - index = (dimX*dimY)*k + i*dimX+j; - if ((i < dimX) && (j < dimY) && (k < dimZ)) { + + index = (dimX*dimY)*k + i*dimX+j; + if ((i < dimX) && (j < dimY) && (k < dimZ)) { grad_magn = (sqrtf(powf(P1[index],2) + powf(P2[index],2) + powf(P3[index],2)))/alpha1; if (grad_magn > 1.0f) { P1[index] /= grad_magn; @@ -322,35 +328,35 @@ __global__ void DualQ_3D_kernel(float *V1, float *V2, float *V3, float *Q1, floa float q1, q2, q3, q11, q22, q33, q44, q55, q66; long index; - + const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; const long k = blockDim.z * blockIdx.z + threadIdx.z; - - index = (dimX*dimY)*k + i*dimX+j; + + index = (dimX*dimY)*k + i*dimX+j; long i1 = (dimX*dimY)*k + (i+1)*dimX+j; long j1 = (dimX*dimY)*k + (i)*dimX+(j+1); long k1 = (dimX*dimY)*(k+1) + (i)*dimX+(j); - - if ((i < dimX) && (j < dimY) && (k < dimZ)) { + + if ((i < dimX) && (j < dimY) && (k < dimZ)) { q1 = 0.0f; q11 = 0.0f; q33 = 0.0f; q2 = 0.0f; q22 = 0.0f; q55 = 0.0f; q3 = 0.0f; q44 = 0.0f; q66 = 0.0f; - + /* boundary conditions (Neuman) */ - if ((i >= 0) && (i < dimX-1)) { - q1 = V1[i1] - V1[index]; + if ((i >= 0) && (i < dimX-1)) { + q1 = V1[i1] - V1[index]; q11 = V2[i1] - V2[index]; q33 = V3[i1] - V3[index]; } if ((j >= 0) && (j < dimY-1)) { - q2 = V2[j1] - V2[index]; + q2 = V2[j1] - V2[index]; q22 = V1[j1] - V1[index]; q55 = V3[j1] - V3[index]; } if ((k >= 0) && (k < dimZ-1)) { q3 = V3[k1] - V3[index]; q44 = V1[k1] - V1[index]; q66 = V2[k1] - V2[index]; } - + Q1[index] += sigma*(q1); /*Q11*/ - Q2[index] += sigma*(q2); /*Q22*/ + Q2[index] += sigma*(q2); /*Q22*/ Q3[index] += sigma*(q3); /*Q33*/ Q4[index] += sigma*(0.5f*(q11 + q22)); /* Q21 / Q12 */ Q5[index] += sigma*(0.5f*(q33 + q44)); /* Q31 / Q13 */ @@ -365,11 +371,11 @@ __global__ void ProjQ_3D_kernel(float *Q1, float *Q2, float *Q3, float *Q4, floa long index; const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - const long k = blockDim.z * blockIdx.z + threadIdx.z; + const long k = blockDim.z * blockIdx.z + threadIdx.z; - index = (dimX*dimY)*k + i*dimX+j; - - if ((i < dimX) && (j < dimY) && (k < dimZ)) { + index = (dimX*dimY)*k + i*dimX+j; + + if ((i < dimX) && (j < dimY) && (k < dimZ)) { grad_magn = sqrtf(powf(Q1[index],2) + powf(Q2[index],2) + powf(Q3[index],2) + 2.0f*powf(Q4[index],2) + 2.0f*powf(Q5[index],2) + 2.0f*powf(Q6[index],2)); grad_magn = grad_magn/alpha0; if (grad_magn > 1.0f) { @@ -382,21 +388,21 @@ __global__ void ProjQ_3D_kernel(float *Q1, float *Q2, float *Q3, float *Q4, floa } } return; -} +} __global__ void DivProjP_3D_kernel(float *U, float *U0, float *P1, float *P2, float *P3, long dimX, long dimY, long dimZ, float lambda, float tau) { float P_v1, P_v2, P_v3, div; long index; const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - const long k = blockDim.z * blockIdx.z + threadIdx.z; - - index = (dimX*dimY)*k + i*dimX+j; + const long k = blockDim.z * blockIdx.z + threadIdx.z; + + index = (dimX*dimY)*k + i*dimX+j; long i1 = (dimX*dimY)*k + (i-1)*dimX+j; long j1 = (dimX*dimY)*k + (i)*dimX+(j-1); - long k1 = (dimX*dimY)*(k-1) + (i)*dimX+(j); - - if ((i < dimX) && (j < dimY) && (k < dimZ)) { + long k1 = (dimX*dimY)*(k-1) + (i)*dimX+(j); + + if ((i < dimX) && (j < dimY) && (k < dimZ)) { if ((i > 0) && (i < dimX-1)) P_v1 = P1[index] - P1[i1]; else if (i == dimX-1) P_v1 = -P1[i1]; @@ -408,13 +414,13 @@ __global__ void DivProjP_3D_kernel(float *U, float *U0, float *P1, float *P2, fl else if (j == 0) P_v2 = P2[index]; else P_v2 = 0.0f; - if ((k > 0) && (k < dimZ-1)) P_v3 = P3[index] - P3[k1]; + if ((k > 0) && (k < dimZ-1)) P_v3 = P3[index] - P3[k1]; else if (k == dimZ-1) P_v3 = -P3[k1]; else if (k == 0) P_v3 = P3[index]; - else P_v3 = 0.0f; - + else P_v3 = 0.0f; + div = P_v1 + P_v2 + P_v3; - U[index] = (lambda*(U[index] + tau*div) + tau*U0[index])/(lambda + tau); + U[index] = (lambda*(U[index] + tau*div) + tau*U0[index])/(lambda + tau); } return; } @@ -425,37 +431,37 @@ __global__ void UpdV_3D_kernel(float *V1, float *V2, float *V3, float *P1, float const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; const long k = blockDim.z * blockIdx.z + threadIdx.z; - - index = (dimX*dimY)*k + i*dimX+j; + + index = (dimX*dimY)*k + i*dimX+j; long i1 = (dimX*dimY)*k + (i-1)*dimX+j; long j1 = (dimX*dimY)*k + (i)*dimX+(j-1); - long k1 = (dimX*dimY)*(k-1) + (i)*dimX+(j); - - /* Q1 - Q11, Q2 - Q22, Q3 - Q33, Q4 - Q21/Q12, Q5 - Q31/Q13, Q6 - Q32/Q23*/ - if ((i < dimX) && (j < dimY) && (k < dimZ)) { + long k1 = (dimX*dimY)*(k-1) + (i)*dimX+(j); - /* boundary conditions (Neuman) */ + /* Q1 - Q11, Q2 - Q22, Q3 - Q33, Q4 - Q21/Q12, Q5 - Q31/Q13, Q6 - Q32/Q23*/ + if ((i < dimX) && (j < dimY) && (k < dimZ)) { + + /* boundary conditions (Neuman) */ if ((i > 0) && (i < dimX-1)) { q1 = Q1[index] - Q1[i1]; - q4x = Q4[index] - Q4[i1]; - q5x = Q5[index] - Q5[i1]; } + q4x = Q4[index] - Q4[i1]; + q5x = Q5[index] - Q5[i1]; } else if (i == 0) { q1 = Q1[index]; - q4x = Q4[index]; - q5x = Q5[index]; } + q4x = Q4[index]; + q5x = Q5[index]; } else if (i == dimX-1) { q1 = -Q1[i1]; - q4x = -Q4[i1]; + q4x = -Q4[i1]; q5x = -Q5[i1]; } else { q1 = 0.0f; q4x = 0.0f; - q5x = 0.0f; } - + q5x = 0.0f; } + if ((j > 0) && (j < dimY-1)) { q2 = Q2[index] - Q2[j1]; q4y = Q4[index] - Q4[j1]; - q6y = Q6[index] - Q6[j1]; } + q6y = Q6[index] - Q6[j1]; } else if (j == dimY-1) { q2 = -Q2[j1]; q4y = -Q4[j1]; @@ -468,12 +474,12 @@ __global__ void UpdV_3D_kernel(float *V1, float *V2, float *V3, float *P1, float q2 = 0.0f; q4y = 0.0f; q6y = 0.0f; - } + } if ((k > 0) && (k < dimZ-1)) { q6z = Q6[index] - Q6[k1]; q5z = Q5[index] - Q5[k1]; - q3 = Q3[index] - Q3[k1]; } + q3 = Q3[index] - Q3[k1]; } else if (k == dimZ-1) { q6z = -Q6[k1]; q5z = -Q5[k1]; @@ -488,27 +494,27 @@ __global__ void UpdV_3D_kernel(float *V1, float *V2, float *V3, float *P1, float q3 = 0.0f; } div1 = q1 + q4y + q5z; - div2 = q4x + q2 + q6z; + div2 = q4x + q2 + q6z; div3 = q5x + q6y + q3; - + V1[index] += tau*(P1[index] + div1); V2[index] += tau*(P2[index] + div2); V3[index] += tau*(P3[index] + div3); } return; -} +} __global__ void copyIm_TGV_kernel3D(float *U, float *U_old, long dimX, long dimY, long dimZ) { long index; const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - const long k = blockDim.z * blockIdx.z + threadIdx.z; - + const long k = blockDim.z * blockIdx.z + threadIdx.z; + index = (dimX*dimY)*k + j*dimX+i; - - if ((i < dimX) && (j < dimY) && (k < dimZ)) { - U_old[index] = U[index]; + + if ((i < dimX) && (j < dimY) && (k < dimZ)) { + U_old[index] = U[index]; } } @@ -517,51 +523,79 @@ __global__ void copyIm_TGV_kernel3D_ar3(float *V1, float *V2, float *V3, float * long index; const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; - const long k = blockDim.z * blockIdx.z + threadIdx.z; - + const long k = blockDim.z * blockIdx.z + threadIdx.z; + index = (dimX*dimY)*k + j*dimX+i; - - if ((i < dimX) && (j < dimY) && (k < dimZ)) { + + if ((i < dimX) && (j < dimY) && (k < dimZ)) { V1_old[index] = V1[index]; V2_old[index] = V2[index]; - V3_old[index] = V3[index]; + V3_old[index] = V3[index]; } } -__global__ void newU_kernel3D(float *U, float *U_old, int dimX, int dimY, int dimZ) +__global__ void newU_kernel3D(float *U, float *U_old, long dimX, long dimY, long dimZ) { long index; const long i = blockDim.x * blockIdx.x + threadIdx.x; const long j = blockDim.y * blockIdx.y + threadIdx.y; const long k = blockDim.z * blockIdx.z + threadIdx.z; - + index = (dimX*dimY)*k + j*dimX+i; - - if ((i < dimX) && (j < dimY) && (k < dimZ)) { + + if ((i < dimX) && (j < dimY) && (k < dimZ)) { U[index] = 2.0f*U[index] - U_old[index]; } -} +} __global__ void newU_kernel3D_ar3(float *V1, float *V2, float *V3, float *V1_old, float *V2_old, float *V3_old, long dimX, long dimY, long dimZ) { - long index; - const long i = blockDim.x * blockIdx.x + threadIdx.x; - const long j = blockDim.y * blockIdx.y + threadIdx.y; - const long k = blockDim.z * blockIdx.z + threadIdx.z; - + long index; + const long i = blockDim.x * blockIdx.x + threadIdx.x; + const long j = blockDim.y * blockIdx.y + threadIdx.y; + const long k = blockDim.z * blockIdx.z + threadIdx.z; + index = (dimX*dimY)*k + j*dimX+i; - - if ((i < dimX) && (j < dimY) && (k < dimZ)) { + + if ((i < dimX) && (j < dimY) && (k < dimZ)) { V1[index] = 2.0f*V1[index] - V1_old[index]; V2[index] = 2.0f*V2[index] - V2_old[index]; V3[index] = 2.0f*V3[index] - V3_old[index]; } -} +} + +__global__ void TGVResidCalc2D_kernel(float *Input1, float *Input2, float* Output, long dimX, long dimY, long num_total) +{ + const long i = blockDim.x * blockIdx.x + threadIdx.x; + const long j = blockDim.y * blockIdx.y + threadIdx.y; + + long index = i + (dimX)*j; + + if (index < num_total) { + Output[index] = Input1[index] - Input2[index]; + } +} + +__global__ void TGVResidCalc3D_kernel(float *Input1, float *Input2, float* Output, long dimX, long dimY, long dimZ, long num_total) +{ + long index; + const long i = blockDim.x * blockIdx.x + threadIdx.x; + const long j = blockDim.y * blockIdx.y + threadIdx.y; + const long k = blockDim.z * blockIdx.z + threadIdx.z; + + index = (dimX*dimY)*k + j*dimX+i; + + if (index < num_total) { + Output[index] = Input1[index] - Input2[index]; + } +} + + /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /************************ MAIN HOST FUNCTION ***********************/ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ -extern "C" int TGV_GPU_main(float *U0, float *U, float lambda, float alpha1, float alpha0, int iterationsNumb, float L2, int dimX, int dimY, int dimZ) +extern "C" int TGV_GPU_main(float *U0, float *U, float *infovector, float lambda, float alpha1, float alpha0, int iterationsNumb, float L2, float epsil, int dimX, int dimY, int dimZ) { int deviceCount = -1; // number of devices @@ -569,21 +603,21 @@ extern "C" int TGV_GPU_main(float *U0, float *U, float lambda, float alpha1, flo if (deviceCount == 0) { fprintf(stderr, "No CUDA devices found\n"); return -1; - } - - long dimTotal = (long)(dimX*dimY*dimZ); + } - - float *U_old, *d_U0, *d_U, *P1, *P2, *Q1, *Q2, *Q3, *V1, *V1_old, *V2, *V2_old, tau, sigma; + long dimTotal = (long)(dimX*dimY*dimZ); + float *U_old, *d_U0, *d_U, *P1, *P2, *Q1, *Q2, *Q3, *V1, *V1_old, *V2, *V2_old, tau, sigma, re; + int n, count; + count = 0; re = 0.0f; tau = powf(L2,-0.5f); sigma = tau; - + CHECK(cudaMalloc((void**)&d_U0,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&d_U,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&U_old,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&P1,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&P2,dimTotal*sizeof(float))); - + CHECK(cudaMalloc((void**)&Q1,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&Q2,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&Q3,dimTotal*sizeof(float))); @@ -591,24 +625,24 @@ extern "C" int TGV_GPU_main(float *U0, float *U, float lambda, float alpha1, flo CHECK(cudaMalloc((void**)&V2,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&V1_old,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&V2_old,dimTotal*sizeof(float))); - + CHECK(cudaMemcpy(d_U0,U0,dimTotal*sizeof(float),cudaMemcpyHostToDevice)); - CHECK(cudaMemcpy(d_U,U0,dimTotal*sizeof(float),cudaMemcpyHostToDevice)); + CHECK(cudaMemcpy(d_U,U0,dimTotal*sizeof(float),cudaMemcpyHostToDevice)); cudaMemset(P1, 0, dimTotal*sizeof(float)); cudaMemset(P2, 0, dimTotal*sizeof(float)); cudaMemset(Q1, 0, dimTotal*sizeof(float)); cudaMemset(Q2, 0, dimTotal*sizeof(float)); cudaMemset(Q3, 0, dimTotal*sizeof(float)); cudaMemset(V1, 0, dimTotal*sizeof(float)); - cudaMemset(V2, 0, dimTotal*sizeof(float)); - + cudaMemset(V2, 0, dimTotal*sizeof(float)); + if (dimZ == 1) { /*2D case */ dim3 dimBlock(BLKXSIZE2D,BLKYSIZE2D); dim3 dimGrid(idivup(dimX,BLKXSIZE2D), idivup(dimY,BLKYSIZE2D)); - - for(int n=0; n < iterationsNumb; n++) { - + + for(n=0; n < iterationsNumb; n++) { + /* Calculate Dual Variable P */ DualP_2D_kernel<<<dimGrid,dimBlock>>>(d_U, V1, V2, P1, P2, (long)(dimX), (long)(dimY), sigma); checkCudaErrors( cudaDeviceSynchronize() ); @@ -616,7 +650,7 @@ extern "C" int TGV_GPU_main(float *U0, float *U, float lambda, float alpha1, flo /*Projection onto convex set for P*/ ProjP_2D_kernel<<<dimGrid,dimBlock>>>(P1, P2, (long)(dimX), (long)(dimY), alpha1); checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); + checkCudaErrors(cudaPeekAtLastError() ); /* Calculate Dual Variable Q */ DualQ_2D_kernel<<<dimGrid,dimBlock>>>(V1, V2, Q1, Q2, Q3, (long)(dimX), (long)(dimY), sigma); checkCudaErrors( cudaDeviceSynchronize() ); @@ -649,30 +683,50 @@ extern "C" int TGV_GPU_main(float *U0, float *U, float lambda, float alpha1, flo newU_kernel_ar2<<<dimGrid,dimBlock>>>(V1, V2, V1_old, V2_old, (long)(dimX), (long)(dimY)); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); + + if ((epsil != 0.0f) && (n % 5 == 0)) { + /* calculate norm - stopping rules using the Thrust library */ + TGVResidCalc2D_kernel<<<dimGrid,dimBlock>>>(d_U, U_old, V1_old, (long)(dimX), (long)(dimY), dimTotal); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + + // setup arguments + square<float> unary_op; + thrust::plus<float> binary_op; + thrust::device_vector<float> d_vec(V1_old, V1_old + dimTotal); + float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); + thrust::device_vector<float> d_vec2(d_U, d_U + dimTotal); + float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); + + // compute norm + re = (reduction/reduction2); + if (re < epsil) count++; + if (count > 3) break; + } } } else { /*3D case */ dim3 dimBlock(BLKXSIZE,BLKYSIZE,BLKZSIZE); dim3 dimGrid(idivup(dimX,BLKXSIZE), idivup(dimY,BLKYSIZE),idivup(dimZ,BLKXSIZE)); - + float *P3, *Q4, *Q5, *Q6, *V3, *V3_old; - - CHECK(cudaMalloc((void**)&P3,dimTotal*sizeof(float))); + + CHECK(cudaMalloc((void**)&P3,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&Q4,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&Q5,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&Q6,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&V3,dimTotal*sizeof(float))); CHECK(cudaMalloc((void**)&V3_old,dimTotal*sizeof(float))); - + cudaMemset(Q4, 0.0f, dimTotal*sizeof(float)); cudaMemset(Q5, 0.0f, dimTotal*sizeof(float)); cudaMemset(Q6, 0.0f, dimTotal*sizeof(float)); cudaMemset(P3, 0.0f, dimTotal*sizeof(float)); - cudaMemset(V3, 0.0f, dimTotal*sizeof(float)); - - for(int n=0; n < iterationsNumb; n++) { - + cudaMemset(V3, 0.0f, dimTotal*sizeof(float)); + + for(n=0; n < iterationsNumb; n++) { + /* Calculate Dual Variable P */ DualP_3D_kernel<<<dimGrid,dimBlock>>>(d_U, V1, V2, V3, P1, P2, P3, (long)(dimX), (long)(dimY), (long)(dimZ), sigma); checkCudaErrors( cudaDeviceSynchronize() ); @@ -702,7 +756,7 @@ extern "C" int TGV_GPU_main(float *U0, float *U, float lambda, float alpha1, flo checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); /*saving V into V_old*/ - copyIm_TGV_kernel3D_ar3<<<dimGrid,dimBlock>>>(V1, V2, V3, V1_old, V2_old, V3_old, (long)(dimX), (long)(dimY), (long)(dimZ)); + copyIm_TGV_kernel3D_ar3<<<dimGrid,dimBlock>>>(V1, V2, V3, V1_old, V2_old, V3_old, (long)(dimX), (long)(dimY), (long)(dimZ)); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); /* upd V*/ @@ -713,23 +767,43 @@ extern "C" int TGV_GPU_main(float *U0, float *U, float lambda, float alpha1, flo newU_kernel3D_ar3<<<dimGrid,dimBlock>>>(V1, V2, V3, V1_old, V2_old, V3_old, (long)(dimX), (long)(dimY), (long)(dimZ)); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - } - + + if ((epsil != 0.0f) && (n % 5 == 0)) { + /* calculate norm - stopping rules using the Thrust library */ + TGVResidCalc3D_kernel<<<dimGrid,dimBlock>>>(d_U, U_old, V1_old, (long)(dimX), (long)(dimY), (long)(dimZ), dimTotal); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + + // setup arguments + square<float> unary_op; + thrust::plus<float> binary_op; + thrust::device_vector<float> d_vec(V1_old, V1_old + dimTotal); + float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); + thrust::device_vector<float> d_vec2(d_U, d_U + dimTotal); + float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); + + // compute norm + re = (reduction/reduction2); + if (re < epsil) count++; + if (count > 3) break; + } + } + CHECK(cudaFree(Q4)); CHECK(cudaFree(Q5)); CHECK(cudaFree(Q6)); CHECK(cudaFree(P3)); CHECK(cudaFree(V3)); - CHECK(cudaFree(V3_old)); + CHECK(cudaFree(V3_old)); } - + CHECK(cudaMemcpy(U,d_U,dimTotal*sizeof(float),cudaMemcpyDeviceToHost)); CHECK(cudaFree(d_U0)); CHECK(cudaFree(d_U)); CHECK(cudaFree(U_old)); CHECK(cudaFree(P1)); CHECK(cudaFree(P2)); - + CHECK(cudaFree(Q1)); CHECK(cudaFree(Q2)); CHECK(cudaFree(Q3)); @@ -738,6 +812,10 @@ extern "C" int TGV_GPU_main(float *U0, float *U, float lambda, float alpha1, flo CHECK(cudaFree(V1_old)); CHECK(cudaFree(V2_old)); - cudaDeviceReset(); + //cudaDeviceReset(); + /*adding info into info_vector */ + infovector[0] = (float)(n); /*iterations number (if stopped earlier based on tolerance)*/ + infovector[1] = re; /* reached tolerance */ + return 0; } diff --git a/src/Core/regularisers_GPU/TGV_GPU_core.h b/src/Core/regularisers_GPU/TGV_GPU_core.h index e8f9c6e..3f820dd 100644 --- a/src/Core/regularisers_GPU/TGV_GPU_core.h +++ b/src/Core/regularisers_GPU/TGV_GPU_core.h @@ -5,6 +5,6 @@ #include <memory.h> #include <stdio.h> -extern "C" CCPI_EXPORT int TGV_GPU_main(float *U0, float *U, float lambda, float alpha1, float alpha0, int iterationsNumb, float L2, int dimX, int dimY, int dimZ); +extern "C" CCPI_EXPORT int TGV_GPU_main(float *U0, float *U, float *infovector, float lambda, float alpha1, float alpha0, int iterationsNumb, float L2, float epsil, int dimX, int dimY, int dimZ); -#endif +#endif diff --git a/src/Core/regularisers_GPU/TV_FGP_GPU_core.cu b/src/Core/regularisers_GPU/TV_FGP_GPU_core.cu index 34be05c..ce2548f 100755 --- a/src/Core/regularisers_GPU/TV_FGP_GPU_core.cu +++ b/src/Core/regularisers_GPU/TV_FGP_GPU_core.cu @@ -370,7 +370,7 @@ extern "C" int TV_FGP_GPU_main(float *Input, float *Output, float *infovector, f /*allocate space for images on device*/ checkCudaErrors( cudaMalloc((void**)&d_input,ImSize*sizeof(float)) ); checkCudaErrors( cudaMalloc((void**)&d_update,ImSize*sizeof(float)) ); - if (epsil != 0.0f) checkCudaErrors( cudaMalloc((void**)&d_update_prev,ImSize*sizeof(float)) ); + if (epsil != 0.0f) checkCudaErrors( cudaMalloc((void**)&d_update_prev,ImSize*sizeof(float)) ); checkCudaErrors( cudaMalloc((void**)&P1,ImSize*sizeof(float)) ); checkCudaErrors( cudaMalloc((void**)&P2,ImSize*sizeof(float)) ); checkCudaErrors( cudaMalloc((void**)&P1_prev,ImSize*sizeof(float)) ); @@ -392,6 +392,12 @@ extern "C" int TV_FGP_GPU_main(float *Input, float *Output, float *infovector, f /* The main kernel */ for (i = 0; i < iter; i++) { + if ((epsil != 0.0f) && (i % 5 == 0)) { + FGPcopy_kernel2D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, dimX, dimY, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + } + /* computing the gradient of the objective function */ Obj_func2D_kernel<<<dimGrid,dimBlock>>>(d_input, d_update, R1, R2, dimX, dimY, ImSize, lambdaPar); checkCudaErrors( cudaDeviceSynchronize() ); @@ -437,21 +443,17 @@ extern "C" int TV_FGP_GPU_main(float *Input, float *Output, float *infovector, f checkCudaErrors(cudaPeekAtLastError() ); // setup arguments - square<float> unary_op; - thrust::plus<float> binary_op; + square<float> unary_op; + thrust::plus<float> binary_op; thrust::device_vector<float> d_vec(P1, P1 + ImSize); - float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); + float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); thrust::device_vector<float> d_vec2(d_update, d_update + ImSize); - float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); + float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); // compute norm re = (reduction/reduction2); if (re < epsil) count++; if (count > 3) break; - - FGPcopy_kernel2D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, dimX, dimY, ImSize); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); } } @@ -506,6 +508,12 @@ extern "C" int TV_FGP_GPU_main(float *Input, float *Output, float *infovector, f /* The main kernel */ for (i = 0; i < iter; i++) { + if ((epsil != 0.0f) && (i % 5 == 0)) { + FGPcopy_kernel3D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, dimX, dimY, dimZ, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + } + /* computing the gradient of the objective function */ Obj_func3D_kernel<<<dimGrid,dimBlock>>>(d_input, d_update, R1, R2, R3, dimX, dimY, dimZ, ImSize, lambdaPar); checkCudaErrors( cudaDeviceSynchronize() ); @@ -549,29 +557,24 @@ extern "C" int TV_FGP_GPU_main(float *Input, float *Output, float *infovector, f tk = tkp1; if ((epsil != 0.0f) && (i % 5 == 0)) { - /* calculate norm - stopping rules using the Thrust library */ - FGPResidCalc3D_kernel<<<dimGrid,dimBlock>>>(d_update, d_update_prev, P1, dimX, dimY, dimZ, ImSize); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); + /* calculate norm - stopping rules using the Thrust library */ + FGPResidCalc3D_kernel<<<dimGrid,dimBlock>>>(d_update, d_update_prev, P1, dimX, dimY, dimZ, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); - // setup arguments + // setup arguments square<float> unary_op; thrust::plus<float> binary_op; thrust::device_vector<float> d_vec(P1, P1 + ImSize); float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); thrust::device_vector<float> d_vec2(d_update, d_update + ImSize); - float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); - - // compute norm - re = (reduction/reduction2); - if (re < epsil) count++; - if (count > 3) break; + float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); - FGPcopy_kernel3D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, dimX, dimY, dimZ, ImSize); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); + // compute norm + re = (reduction/reduction2); + if (re < epsil) count++; + if (count > 3) break; } - } /***************************************************************/ //copy result matrix from device to host memory diff --git a/src/Core/regularisers_GPU/TV_ROF_GPU_core.cu b/src/Core/regularisers_GPU/TV_ROF_GPU_core.cu index e14681c..193cf53 100755 --- a/src/Core/regularisers_GPU/TV_ROF_GPU_core.cu +++ b/src/Core/regularisers_GPU/TV_ROF_GPU_core.cu @@ -379,10 +379,16 @@ extern "C" int TV_ROF_GPU_main(float* Input, float* Output, float *infovector, f dim3 dimGrid(idivup(N,BLKXSIZE2D), idivup(M,BLKYSIZE2D)); for(n=0; n < iter; n++) { + + if ((epsil != 0.0f) && (n % 5 == 0)) { + ROFcopy_kernel2D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, N, M, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + } /* calculate differences */ D1_func2D<<<dimGrid,dimBlock>>>(d_update, d_D1, N, M); CHECK(cudaDeviceSynchronize()); - D2_func2D<<<dimGrid,dimBlock>>>(d_update, d_D2, N, M); + D2_func2D<<<dimGrid,dimBlock>>>(d_update, d_D2, N, M); CHECK(cudaDeviceSynchronize()); /*running main kernel*/ TV_kernel2D<<<dimGrid,dimBlock>>>(d_D1, d_D2, d_update, d_input, lambdaPar, tau, N, M); @@ -395,21 +401,17 @@ extern "C" int TV_ROF_GPU_main(float* Input, float* Output, float *infovector, f checkCudaErrors( cudaPeekAtLastError() ); // setup arguments - square<float> unary_op; - thrust::plus<float> binary_op; + square<float> unary_op; + thrust::plus<float> binary_op; thrust::device_vector<float> d_vec(d_D1, d_D1 + ImSize); - float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); + float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); thrust::device_vector<float> d_vec2(d_update, d_update + ImSize); - float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); + float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); // compute norm re = (reduction/reduction2); if (re < epsil) count++; if (count > 3) break; - - ROFcopy_kernel2D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, N, M, ImSize); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); } } @@ -423,10 +425,17 @@ extern "C" int TV_ROF_GPU_main(float* Input, float* Output, float *infovector, f CHECK(cudaMalloc((void**)&d_D3,N*M*Z*sizeof(float))); for(n=0; n < iter; n++) { + + if ((epsil != 0.0f) && (n % 5 == 0)) { + ROFcopy_kernel3D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, N, M, Z, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + } + /* calculate differences */ D1_func3D<<<dimGrid,dimBlock>>>(d_update, d_D1, N, M, Z); CHECK(cudaDeviceSynchronize()); - D2_func3D<<<dimGrid,dimBlock>>>(d_update, d_D2, N, M, Z); + D2_func3D<<<dimGrid,dimBlock>>>(d_update, d_D2, N, M, Z); CHECK(cudaDeviceSynchronize()); D3_func3D<<<dimGrid,dimBlock>>>(d_update, d_D3, N, M, Z); CHECK(cudaDeviceSynchronize()); @@ -453,9 +462,6 @@ extern "C" int TV_ROF_GPU_main(float* Input, float* Output, float *infovector, f if (re < epsil) count++; if (count > 3) break; - ROFcopy_kernel3D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, N, M, Z, ImSize); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); } diff --git a/src/Core/regularisers_GPU/TV_SB_GPU_core.cu b/src/Core/regularisers_GPU/TV_SB_GPU_core.cu index b163791..0353868 100755 --- a/src/Core/regularisers_GPU/TV_SB_GPU_core.cu +++ b/src/Core/regularisers_GPU/TV_SB_GPU_core.cu @@ -440,10 +440,6 @@ extern "C" int TV_SB_GPU_main(float *Input, float *Output, float *infovector, fl re = (reduction/reduction2); if (re < epsil) count++; if (count > 3) break; - - SBcopy_kernel2D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, dimX, dimY, DimTotal); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); } } /***************************************************************/ @@ -510,11 +506,7 @@ extern "C" int TV_SB_GPU_main(float *Input, float *Output, float *infovector, fl re = (reduction/reduction2); if (re < epsil) count++; if (count > 3) break; - - SBcopy_kernel3D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, dimX, dimY, dimZ, DimTotal); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); - } + } } cudaFree(Dz); cudaFree(Bz); diff --git a/src/Core/regularisers_GPU/dTV_FGP_GPU_core.cu b/src/Core/regularisers_GPU/dTV_FGP_GPU_core.cu index 9db594e..89fca06 100644 --- a/src/Core/regularisers_GPU/dTV_FGP_GPU_core.cu +++ b/src/Core/regularisers_GPU/dTV_FGP_GPU_core.cu @@ -15,9 +15,10 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -*/ +*/ #include "shared.h" #include "dTV_FGP_GPU_core.h" +#include <thrust/functional.h> #include <thrust/device_vector.h> #include <thrust/transform_reduce.h> @@ -31,19 +32,19 @@ limitations under the License. * 3. lambdaPar - regularization parameter [REQUIRED] * 4. Number of iterations [OPTIONAL] * 5. eplsilon: tolerance constant [OPTIONAL] - * 6. eta: smoothing constant to calculate gradient of the reference [OPTIONAL] * + * 6. eta: smoothing constant to calculate gradient of the reference [OPTIONAL] * * 7. TV-type: methodTV - 'iso' (0) or 'l1' (1) [OPTIONAL] * 8. nonneg: 'nonnegativity (0 is OFF by default) [OPTIONAL] - * 9. print information: 0 (off) or 1 (on) [OPTIONAL] - * + * Output: * [1] Filtered/regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the Matlab's codes and papers by * [1] Amir Beck and Marc Teboulle, "Fast Gradient-Based Algorithms for Constrained Total Variation Image Denoising and Deblurring Problems" * [2] M. J. Ehrhardt and M. M. Betcke, Multi-Contrast MRI Reconstruction with Structure-Guided Total Variation, SIAM Journal on Imaging Sciences 9(3), pp. 1084–1106 */ - + #define BLKXSIZE2D 16 #define BLKYSIZE2D 16 @@ -61,43 +62,43 @@ limitations under the License. __global__ void GradNorm_func2D_kernel(float *Refd, float *Refd_x, float *Refd_y, float eta, int N, int M, int ImSize) { - + float val1, val2, gradX, gradY, magn; //calculate each thread global index const int xIndex=blockIdx.x*blockDim.x+threadIdx.x; const int yIndex=blockIdx.y*blockDim.y+threadIdx.y; - - int index = xIndex + N*yIndex; - - if ((xIndex < N) && (yIndex < M)) { + + int index = xIndex + N*yIndex; + + if ((xIndex < N) && (yIndex < M)) { /* boundary conditions */ if (xIndex >= N-1) val1 = 0.0f; else val1 = Refd[(xIndex+1) + N*yIndex]; - if (yIndex >= M-1) val2 = 0.0f; else val2 = Refd[(xIndex) + N*(yIndex + 1)]; - + if (yIndex >= M-1) val2 = 0.0f; else val2 = Refd[(xIndex) + N*(yIndex + 1)]; + gradX = val1 - Refd[index]; gradY = val2 - Refd[index]; magn = pow(gradX,2) + pow(gradY,2); magn = sqrt(magn + pow(eta,2)); Refd_x[index] = gradX/magn; - Refd_y[index] = gradY/magn; + Refd_y[index] = gradY/magn; } return; } __global__ void ProjectVect_func2D_kernel(float *R1, float *R2, float *Refd_x, float *Refd_y, int N, int M, int ImSize) { - + float in_prod; //calculate each thread global index const int xIndex=blockIdx.x*blockDim.x+threadIdx.x; const int yIndex=blockIdx.y*blockDim.y+threadIdx.y; - - int index = xIndex + N*yIndex; - + + int index = xIndex + N*yIndex; + if ((xIndex < N) && (yIndex < M)) { in_prod = R1[index]*Refd_x[index] + R2[index]*Refd_y[index]; /* calculate inner product */ R1[index] = R1[index] - in_prod*Refd_x[index]; - R2[index] = R2[index] - in_prod*Refd_y[index]; + R2[index] = R2[index] - in_prod*Refd_y[index]; } return; } @@ -105,19 +106,19 @@ __global__ void ProjectVect_func2D_kernel(float *R1, float *R2, float *Refd_x, f __global__ void Obj_dfunc2D_kernel(float *Ad, float *D, float *R1, float *R2, int N, int M, int ImSize, float lambda) { - + float val1,val2; - + //calculate each thread global index const int xIndex=blockIdx.x*blockDim.x+threadIdx.x; const int yIndex=blockIdx.y*blockDim.y+threadIdx.y; - - int index = xIndex + N*yIndex; - - if ((xIndex < N) && (yIndex < M)) { + + int index = xIndex + N*yIndex; + + if ((xIndex < N) && (yIndex < M)) { if (xIndex <= 0) {val1 = 0.0f;} else {val1 = R1[(xIndex-1) + N*yIndex];} if (yIndex <= 0) {val2 = 0.0f;} else {val2 = R2[xIndex + N*(yIndex-1)];} - + //Write final result to global memory D[index] = Ad[index] - lambda*(R1[index] + R2[index] - val1 - val2); } @@ -126,25 +127,25 @@ __global__ void Obj_dfunc2D_kernel(float *Ad, float *D, float *R1, float *R2, in __global__ void Grad_dfunc2D_kernel(float *P1, float *P2, float *D, float *R1, float *R2, float *Refd_x, float *Refd_y, int N, int M, int ImSize, float multip) { - + float val1,val2,in_prod; - + //calculate each thread global index const int xIndex=blockIdx.x*blockDim.x+threadIdx.x; const int yIndex=blockIdx.y*blockDim.y+threadIdx.y; - + int index = xIndex + N*yIndex; - - if ((xIndex < N) && (yIndex < M)) { - + + if ((xIndex < N) && (yIndex < M)) { + /* boundary conditions */ if (xIndex >= N-1) val1 = 0.0f; else val1 = D[index] - D[(xIndex+1) + N*yIndex]; if (yIndex >= M-1) val2 = 0.0f; else val2 = D[index] - D[(xIndex) + N*(yIndex + 1)]; - + in_prod = val1*Refd_x[index] + val2*Refd_y[index]; /* calculate inner product */ val1 = val1 - in_prod*Refd_x[index]; - val2 = val2 - in_prod*Refd_y[index]; - + val2 = val2 - in_prod*Refd_y[index]; + //Write final result to global memory P1[index] = R1[index] + multip*val1; P2[index] = R2[index] + multip*val2; @@ -154,16 +155,16 @@ __global__ void Grad_dfunc2D_kernel(float *P1, float *P2, float *D, float *R1, f __global__ void Proj_dfunc2D_iso_kernel(float *P1, float *P2, int N, int M, int ImSize) { - - float denom; + + float denom; //calculate each thread global index const int xIndex=blockIdx.x*blockDim.x+threadIdx.x; const int yIndex=blockIdx.y*blockDim.y+threadIdx.y; - + int index = xIndex + N*yIndex; - - if ((xIndex < N) && (yIndex < M)) { - denom = pow(P1[index],2) + pow(P2[index],2); + + if ((xIndex < N) && (yIndex < M)) { + denom = pow(P1[index],2) + pow(P2[index],2); if (denom > 1.0f) { P1[index] = P1[index]/sqrt(denom); P2[index] = P2[index]/sqrt(denom); @@ -173,15 +174,15 @@ __global__ void Proj_dfunc2D_iso_kernel(float *P1, float *P2, int N, int M, int } __global__ void Proj_dfunc2D_aniso_kernel(float *P1, float *P2, int N, int M, int ImSize) { - - float val1, val2; + + float val1, val2; //calculate each thread global index const int xIndex=blockIdx.x*blockDim.x+threadIdx.x; const int yIndex=blockIdx.y*blockDim.y+threadIdx.y; - + int index = xIndex + N*yIndex; - - if ((xIndex < N) && (yIndex < M)) { + + if ((xIndex < N) && (yIndex < M)) { val1 = abs(P1[index]); val2 = abs(P2[index]); if (val1 < 1.0f) {val1 = 1.0f;} @@ -196,10 +197,10 @@ __global__ void Rupd_dfunc2D_kernel(float *P1, float *P1_old, float *P2, float * //calculate each thread global index const int xIndex=blockIdx.x*blockDim.x+threadIdx.x; const int yIndex=blockIdx.y*blockDim.y+threadIdx.y; - + int index = xIndex + N*yIndex; - - if ((xIndex < N) && (yIndex < M)) { + + if ((xIndex < N) && (yIndex < M)) { R1[index] = P1[index] + multip2*(P1[index] - P1_old[index]); R2[index] = P2[index] + multip2*(P2[index] - P2_old[index]); } @@ -209,9 +210,9 @@ __global__ void dTVnonneg2D_kernel(float* Output, int N, int M, int num_total) { int xIndex = blockDim.x * blockIdx.x + threadIdx.x; int yIndex = blockDim.y * blockIdx.y + threadIdx.y; - + int index = xIndex + N*yIndex; - + if (index < num_total) { if (Output[index] < 0.0f) Output[index] = 0.0f; } @@ -220,9 +221,9 @@ __global__ void dTVcopy_kernel2D(float *Input, float* Output, int N, int M, int { int xIndex = blockDim.x * blockIdx.x + threadIdx.x; int yIndex = blockDim.y * blockIdx.y + threadIdx.y; - + int index = xIndex + N*yIndex; - + if (index < num_total) { Output[index] = Input[index]; } @@ -233,9 +234,9 @@ __global__ void dTVcopy_kernel3D(float *Input, float* Output, int N, int M, int int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + int index = (N*M)*k + i + N*j; - + if (index < num_total) { Output[index] = Input[index]; } @@ -245,9 +246,9 @@ __global__ void dTVResidCalc2D_kernel(float *Input1, float *Input2, float* Outpu { int xIndex = blockDim.x * blockIdx.x + threadIdx.x; int yIndex = blockDim.y * blockIdx.y + threadIdx.y; - + int index = xIndex + N*yIndex; - + if (index < num_total) { Output[index] = Input1[index] - Input2[index]; } @@ -258,9 +259,9 @@ __global__ void dTVResidCalc3D_kernel(float *Input1, float *Input2, float* Outpu int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + int index = (N*M)*k + i + N*j; - + if (index < num_total) { Output[index] = Input1[index] - Input2[index]; } @@ -271,21 +272,21 @@ __global__ void dTVResidCalc3D_kernel(float *Input1, float *Input2, float* Outpu /************************************************/ __global__ void GradNorm_func3D_kernel(float *Refd, float *Refd_x, float *Refd_y, float *Refd_z, float eta, int N, int M, int Z, int ImSize) { - + float val1, val2, val3, gradX, gradY, gradZ, magn; //calculate each thread global index int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + int index = (N*M)*k + i + N*j; - - if ((i < N) && (j < M) && (k < Z)) { + + if ((i < N) && (j < M) && (k < Z)) { /* boundary conditions */ if (i >= N-1) val1 = 0.0f; else val1 = Refd[(N*M)*k + (i+1) + N*j]; if (j >= M-1) val2 = 0.0f; else val2 = Refd[(N*M)*k + i + N*(j+1)]; if (k >= Z-1) val3 = 0.0f; else val3 = Refd[(N*M)*(k+1) + i + N*j]; - + gradX = val1 - Refd[index]; gradY = val2 - Refd[index]; gradZ = val3 - Refd[index]; @@ -300,18 +301,18 @@ __global__ void GradNorm_func3D_kernel(float *Refd, float *Refd_x, float *Refd_y __global__ void ProjectVect_func3D_kernel(float *R1, float *R2, float *R3, float *Refd_x, float *Refd_y, float *Refd_z, int N, int M, int Z, int ImSize) { - + float in_prod; //calculate each thread global index int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + int index = (N*M)*k + i + N*j; - + if ((i < N) && (j < M) && (k < Z)) { in_prod = R1[index]*Refd_x[index] + R2[index]*Refd_y[index] + R3[index]*Refd_z[index]; /* calculate inner product */ - + R1[index] = R1[index] - in_prod*Refd_x[index]; R2[index] = R2[index] - in_prod*Refd_y[index]; R3[index] = R3[index] - in_prod*Refd_z[index]; @@ -322,16 +323,16 @@ __global__ void ProjectVect_func3D_kernel(float *R1, float *R2, float *R3, float __global__ void Obj_dfunc3D_kernel(float *Ad, float *D, float *R1, float *R2, float *R3, int N, int M, int Z, int ImSize, float lambda) { - + float val1,val2,val3; - + //calculate each thread global index int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + int index = (N*M)*k + i + N*j; - + if ((i < N) && (j < M) && (k < Z)) { if (i <= 0) {val1 = 0.0f;} else {val1 = R1[(N*M)*(k) + (i-1) + N*j];} if (j <= 0) {val2 = 0.0f;} else {val2 = R2[(N*M)*(k) + i + N*(j-1)];} @@ -344,27 +345,27 @@ __global__ void Obj_dfunc3D_kernel(float *Ad, float *D, float *R1, float *R2, fl __global__ void Grad_dfunc3D_kernel(float *P1, float *P2, float *P3, float *D, float *R1, float *R2, float *R3, float *Refd_x, float *Refd_y, float *Refd_z, int N, int M, int Z, int ImSize, float multip) { - + float val1,val2,val3,in_prod; - + //calculate each thread global index int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + int index = (N*M)*k + i + N*j; - + if ((i < N) && (j < M) && (k < Z)) { /* boundary conditions */ if (i >= N-1) val1 = 0.0f; else val1 = D[index] - D[(N*M)*(k) + (i+1) + N*j]; if (j >= M-1) val2 = 0.0f; else val2 = D[index] - D[(N*M)*(k) + i + N*(j+1)]; - if (k >= Z-1) val3 = 0.0f; else val3 = D[index] - D[(N*M)*(k+1) + i + N*j]; - + if (k >= Z-1) val3 = 0.0f; else val3 = D[index] - D[(N*M)*(k+1) + i + N*j]; + in_prod = val1*Refd_x[index] + val2*Refd_y[index] + val3*Refd_z[index]; /* calculate inner product */ val1 = val1 - in_prod*Refd_x[index]; val2 = val2 - in_prod*Refd_y[index]; val3 = val3 - in_prod*Refd_z[index]; - + //Write final result to global memory P1[index] = R1[index] + multip*val1; P2[index] = R2[index] + multip*val2; @@ -375,18 +376,18 @@ __global__ void Grad_dfunc3D_kernel(float *P1, float *P2, float *P3, float *D, f __global__ void Proj_dfunc3D_iso_kernel(float *P1, float *P2, float *P3, int N, int M, int Z, int ImSize) { - - float denom,sq_denom; + + float denom,sq_denom; //calculate each thread global index int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + int index = (N*M)*k + i + N*j; - + if ((i < N) && (j < M) && (k < Z)) { denom = pow(P1[index],2) + pow(P2[index],2) + pow(P3[index],2); - + if (denom > 1.0f) { sq_denom = 1.0f/sqrt(denom); P1[index] = P1[index]*sq_denom; @@ -399,15 +400,15 @@ __global__ void Proj_dfunc3D_iso_kernel(float *P1, float *P2, float *P3, int N, __global__ void Proj_dfunc3D_aniso_kernel(float *P1, float *P2, float *P3, int N, int M, int Z, int ImSize) { - - float val1, val2, val3; + + float val1, val2, val3; //calculate each thread global index int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + int index = (N*M)*k + i + N*j; - + if ((i < N) && (j < M) && (k < Z)) { val1 = abs(P1[index]); val2 = abs(P2[index]); @@ -429,10 +430,10 @@ __global__ void Rupd_dfunc3D_kernel(float *P1, float *P1_old, float *P2, float * int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + int index = (N*M)*k + i + N*j; - - if ((i < N) && (j < M) && (k < Z)) { + + if ((i < N) && (j < M) && (k < Z)) { R1[index] = P1[index] + multip2*(P1[index] - P1_old[index]); R2[index] = P2[index] + multip2*(P2[index] - P2_old[index]); R3[index] = P3[index] + multip2*(P3[index] - P3_old[index]); @@ -445,9 +446,9 @@ __global__ void dTVnonneg3D_kernel(float* Output, int N, int M, int Z, int num_t int i = blockDim.x * blockIdx.x + threadIdx.x; int j = blockDim.y * blockIdx.y + threadIdx.y; int k = blockDim.z * blockIdx.z + threadIdx.z; - + int index = (N*M)*k + i + N*j; - + if (index < num_total) { if (Output[index] < 0.0f) Output[index] = 0.0f; } @@ -455,7 +456,7 @@ __global__ void dTVnonneg3D_kernel(float* Output, int N, int M, int Z, int num_t /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ ////////////MAIN HOST FUNCTION /////////////// -extern "C" int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, float lambdaPar, int iter, float epsil, float eta, int methodTV, int nonneg, int printM, int dimX, int dimY, int dimZ) +extern "C" int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, float *infovector, float lambdaPar, int iter, float epsil, float eta, int methodTV, int nonneg, int dimX, int dimY, int dimZ) { int deviceCount = -1; // number of devices cudaGetDeviceCount(&deviceCount); @@ -463,20 +464,21 @@ extern "C" int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, fl fprintf(stderr, "No CUDA devices found\n"); return -1; } - + int count = 0, i; - float re, multip,multip2; - float tk = 1.0f; + float re, multip,multip2; + re = 0.0f; + float tk = 1.0f; float tkp1=1.0f; - + if (dimZ <= 1) { /*2D verson*/ - int ImSize = dimX*dimY; + int ImSize = dimX*dimY; float *d_input, *d_update=NULL, *d_update_prev=NULL, *P1=NULL, *P2=NULL, *P1_prev=NULL, *P2_prev=NULL, *R1=NULL, *R2=NULL, *InputRef_x=NULL, *InputRef_y=NULL, *d_InputRef=NULL; - + dim3 dimBlock(BLKXSIZE2D,BLKYSIZE2D); dim3 dimGrid(idivup(dimX,BLKXSIZE2D), idivup(dimY,BLKYSIZE2D)); - + /*allocate space for images on device*/ checkCudaErrors( cudaMalloc((void**)&d_input,ImSize*sizeof(float)) ); checkCudaErrors( cudaMalloc((void**)&d_update,ImSize*sizeof(float)) ); @@ -490,10 +492,10 @@ extern "C" int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, fl checkCudaErrors( cudaMalloc((void**)&d_InputRef,ImSize*sizeof(float)) ); checkCudaErrors( cudaMalloc((void**)&InputRef_x,ImSize*sizeof(float)) ); checkCudaErrors( cudaMalloc((void**)&InputRef_y,ImSize*sizeof(float)) ); - + checkCudaErrors( cudaMemcpy(d_input,Input,ImSize*sizeof(float),cudaMemcpyHostToDevice)); checkCudaErrors( cudaMemcpy(d_InputRef,InputRef,ImSize*sizeof(float),cudaMemcpyHostToDevice)); - + cudaMemset(P1, 0, ImSize*sizeof(float)); cudaMemset(P2, 0, ImSize*sizeof(float)); cudaMemset(P1_prev, 0, ImSize*sizeof(float)); @@ -502,85 +504,91 @@ extern "C" int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, fl cudaMemset(R2, 0, ImSize*sizeof(float)); cudaMemset(InputRef_x, 0, ImSize*sizeof(float)); cudaMemset(InputRef_y, 0, ImSize*sizeof(float)); - + /******************** Run CUDA 2D kernel here ********************/ multip = (1.0f/(8.0f*lambdaPar)); /* calculate gradient vectors for the reference */ GradNorm_func2D_kernel<<<dimGrid,dimBlock>>>(d_InputRef, InputRef_x, InputRef_y, eta, dimX, dimY, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + /* The main kernel */ for (i = 0; i < iter; i++) { - - /*projects a 2D vector field R-1,2 onto the orthogonal complement of another 2D vector field InputRef_xy*/ + + if ((epsil != 0.0f) && (i % 5 == 0)) { + dTVcopy_kernel2D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, dimX, dimY, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + } + + /*projects a 2D vector field R-1,2 onto the orthogonal complement of another 2D vector field InputRef_xy*/ ProjectVect_func2D_kernel<<<dimGrid,dimBlock>>>(R1, R2, InputRef_x, InputRef_y, dimX, dimY, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + /* computing the gradient of the objective function */ Obj_dfunc2D_kernel<<<dimGrid,dimBlock>>>(d_input, d_update, R1, R2, dimX, dimY, ImSize, lambdaPar); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + if (nonneg != 0) { dTVnonneg2D_kernel<<<dimGrid,dimBlock>>>(d_update, dimX, dimY, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); } - + /*Taking a step towards minus of the gradient*/ Grad_dfunc2D_kernel<<<dimGrid,dimBlock>>>(P1, P2, d_update, R1, R2, InputRef_x, InputRef_y, dimX, dimY, ImSize, multip); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + /* projection step */ if (methodTV == 0) Proj_dfunc2D_iso_kernel<<<dimGrid,dimBlock>>>(P1, P2, dimX, dimY, ImSize); /*isotropic TV*/ - else Proj_dfunc2D_aniso_kernel<<<dimGrid,dimBlock>>>(P1, P2, dimX, dimY, ImSize); /*anisotropic TV*/ + else Proj_dfunc2D_aniso_kernel<<<dimGrid,dimBlock>>>(P1, P2, dimX, dimY, ImSize); /*anisotropic TV*/ checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + tkp1 = (1.0f + sqrt(1.0f + 4.0f*tk*tk))*0.5f; multip2 = ((tk-1.0f)/tkp1); - + Rupd_dfunc2D_kernel<<<dimGrid,dimBlock>>>(P1, P1_prev, P2, P2_prev, R1, R2, tkp1, tk, multip2, dimX, dimY, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - - if (epsil != 0.0f) { - /* calculate norm - stopping rules using the Thrust library */ - dTVResidCalc2D_kernel<<<dimGrid,dimBlock>>>(d_update, d_update_prev, P1_prev, dimX, dimY, ImSize); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); - - // thrust::device_vector<float> d_vec(P1_prev, P1_prev + ImSize); - // float reduction = sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), square(), 0.0f, thrust::plus<float>())); - // thrust::device_vector<float> d_vec2(d_update, d_update + ImSize); - // float reduction2 = sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), square(), 0.0f, thrust::plus<float>())); - - // re = (reduction/reduction2); - // if (re < epsil) count++; - // if (count > 4) break; - - dTVcopy_kernel2D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, dimX, dimY, ImSize); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); - } - + dTVcopy_kernel2D<<<dimGrid,dimBlock>>>(P1, P1_prev, dimX, dimY, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + dTVcopy_kernel2D<<<dimGrid,dimBlock>>>(P2, P2_prev, dimX, dimY, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); - + checkCudaErrors(cudaPeekAtLastError() ); + tk = tkp1; + + if ((epsil != 0.0f) && (i % 5 == 0)) { + /* calculate norm - stopping rules using the Thrust library */ + dTVResidCalc2D_kernel<<<dimGrid,dimBlock>>>(d_update, d_update_prev, P1, dimX, dimY, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + + // setup arguments + square<float> unary_op; + thrust::plus<float> binary_op; + thrust::device_vector<float> d_vec(P1, P1 + ImSize); + float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); + thrust::device_vector<float> d_vec2(d_update, d_update + ImSize); + float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); + + // compute norm + re = (reduction/reduction2); + if (re < epsil) count++; + if (count > 3) break; + } + } - if (printM == 1) printf("FGP-dTV iterations stopped at iteration %i \n", i); - /***************************************************************/ + /***************************************************************/ //copy result matrix from device to host memory cudaMemcpy(Output,d_update,ImSize*sizeof(float),cudaMemcpyDeviceToHost); - + cudaFree(d_input); cudaFree(d_update); if (epsil != 0.0f) cudaFree(d_update_prev); @@ -590,19 +598,19 @@ extern "C" int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, fl cudaFree(P2_prev); cudaFree(R1); cudaFree(R2); - + cudaFree(d_InputRef); cudaFree(InputRef_x); cudaFree(InputRef_y); } else { /*3D verson*/ - int ImSize = dimX*dimY*dimZ; + int ImSize = dimX*dimY*dimZ; float *d_input, *d_update=NULL, *d_update_prev, *P1=NULL, *P2=NULL, *P3=NULL, *P1_prev=NULL, *P2_prev=NULL, *P3_prev=NULL, *R1=NULL, *R2=NULL, *R3=NULL, *InputRef_x=NULL, *InputRef_y=NULL, *InputRef_z=NULL, *d_InputRef=NULL; - + dim3 dimBlock(BLKXSIZE,BLKYSIZE,BLKZSIZE); dim3 dimGrid(idivup(dimX,BLKXSIZE), idivup(dimY,BLKYSIZE),idivup(dimZ,BLKZSIZE)); - + /*allocate space for images on device*/ checkCudaErrors( cudaMalloc((void**)&d_input,ImSize*sizeof(float)) ); checkCudaErrors( cudaMalloc((void**)&d_update,ImSize*sizeof(float)) ); @@ -619,11 +627,11 @@ extern "C" int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, fl checkCudaErrors( cudaMalloc((void**)&d_InputRef,ImSize*sizeof(float)) ); checkCudaErrors( cudaMalloc((void**)&InputRef_x,ImSize*sizeof(float)) ); checkCudaErrors( cudaMalloc((void**)&InputRef_y,ImSize*sizeof(float)) ); - checkCudaErrors( cudaMalloc((void**)&InputRef_z,ImSize*sizeof(float)) ); - + checkCudaErrors( cudaMalloc((void**)&InputRef_z,ImSize*sizeof(float)) ); + checkCudaErrors( cudaMemcpy(d_input,Input,ImSize*sizeof(float),cudaMemcpyHostToDevice)); checkCudaErrors( cudaMemcpy(d_InputRef,InputRef,ImSize*sizeof(float),cudaMemcpyHostToDevice)); - + cudaMemset(P1, 0, ImSize*sizeof(float)); cudaMemset(P2, 0, ImSize*sizeof(float)); cudaMemset(P3, 0, ImSize*sizeof(float)); @@ -636,89 +644,93 @@ extern "C" int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, fl cudaMemset(InputRef_x, 0, ImSize*sizeof(float)); cudaMemset(InputRef_y, 0, ImSize*sizeof(float)); cudaMemset(InputRef_z, 0, ImSize*sizeof(float)); - - /********************** Run CUDA 3D kernel here ********************/ + + /********************** Run CUDA 3D kernel here ********************/ multip = (1.0f/(26.0f*lambdaPar)); /* calculate gradient vectors for the reference */ GradNorm_func3D_kernel<<<dimGrid,dimBlock>>>(d_InputRef, InputRef_x, InputRef_y, InputRef_z, eta, dimX, dimY, dimZ, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + /* The main kernel */ for (i = 0; i < iter; i++) { - /*projects a 3D vector field R-1,2,3 onto the orthogonal complement of another 3D vector field InputRef_xyz*/ + if ((epsil != 0.0f) && (i % 5 == 0)) { + dTVcopy_kernel3D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, dimX, dimY, dimZ, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + } + + /*projects a 3D vector field R-1,2,3 onto the orthogonal complement of another 3D vector field InputRef_xyz*/ ProjectVect_func3D_kernel<<<dimGrid,dimBlock>>>(R1, R2, R3, InputRef_x, InputRef_y, InputRef_z, dimX, dimY, dimZ, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + /* computing the gradient of the objective function */ Obj_dfunc3D_kernel<<<dimGrid,dimBlock>>>(d_input, d_update, R1, R2, R3, dimX, dimY, dimZ, ImSize, lambdaPar); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + if (nonneg != 0) { dTVnonneg3D_kernel<<<dimGrid,dimBlock>>>(d_update, dimX, dimY, dimZ, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); } - + /*Taking a step towards minus of the gradient*/ Grad_dfunc3D_kernel<<<dimGrid,dimBlock>>>(P1, P2, P3, d_update, R1, R2, R3, InputRef_x, InputRef_y, InputRef_z, dimX, dimY, dimZ, ImSize, multip); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + /* projection step */ if (methodTV == 0) Proj_dfunc3D_iso_kernel<<<dimGrid,dimBlock>>>(P1, P2, P3, dimX, dimY, dimZ, ImSize); /* isotropic kernel */ else Proj_dfunc3D_aniso_kernel<<<dimGrid,dimBlock>>>(P1, P2, P3, dimX, dimY, dimZ, ImSize); /* anisotropic kernel */ checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + tkp1 = (1.0f + sqrt(1.0f + 4.0f*tk*tk))*0.5f; multip2 = ((tk-1.0f)/tkp1); - + Rupd_dfunc3D_kernel<<<dimGrid,dimBlock>>>(P1, P1_prev, P2, P2_prev, P3, P3_prev, R1, R2, R3, tkp1, tk, multip2, dimX, dimY, dimZ, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - - if (epsil != 0.0f) { - /* calculate norm - stopping rules using the Thrust library */ - dTVResidCalc3D_kernel<<<dimGrid,dimBlock>>>(d_update, d_update_prev, P1_prev, dimX, dimY, dimZ, ImSize); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); - - // thrust::device_vector<float> d_vec(P1_prev, P1_prev + ImSize); - // float reduction = sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), square(), 0.0f, thrust::plus<float>())); - // thrust::device_vector<float> d_vec2(d_update, d_update + ImSize); - // float reduction2 = sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), square(), 0.0f, thrust::plus<float>())); - - // re = (reduction/reduction2); - // if (re < epsil) count++; - // if (count > 4) break; - - dTVcopy_kernel3D<<<dimGrid,dimBlock>>>(d_update, d_update_prev, dimX, dimY, dimZ, ImSize); - checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); - } - + dTVcopy_kernel3D<<<dimGrid,dimBlock>>>(P1, P1_prev, dimX, dimY, dimZ, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); checkCudaErrors(cudaPeekAtLastError() ); - + dTVcopy_kernel3D<<<dimGrid,dimBlock>>>(P2, P2_prev, dimX, dimY, dimZ, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); - + checkCudaErrors(cudaPeekAtLastError() ); + dTVcopy_kernel3D<<<dimGrid,dimBlock>>>(P3, P3_prev, dimX, dimY, dimZ, ImSize); checkCudaErrors( cudaDeviceSynchronize() ); - checkCudaErrors(cudaPeekAtLastError() ); - + checkCudaErrors(cudaPeekAtLastError() ); + tk = tkp1; + if ((epsil != 0.0f) && (i % 5 == 0)) { + /* calculate norm - stopping rules using the Thrust library */ + dTVResidCalc3D_kernel<<<dimGrid,dimBlock>>>(d_update, d_update_prev, P1, dimX, dimY, dimZ, ImSize); + checkCudaErrors( cudaDeviceSynchronize() ); + checkCudaErrors(cudaPeekAtLastError() ); + + // setup arguments + square<float> unary_op; + thrust::plus<float> binary_op; + thrust::device_vector<float> d_vec(P1, P1 + ImSize); + float reduction = std::sqrt(thrust::transform_reduce(d_vec.begin(), d_vec.end(), unary_op, 0.0f, binary_op)); + thrust::device_vector<float> d_vec2(d_update, d_update + ImSize); + float reduction2 = std::sqrt(thrust::transform_reduce(d_vec2.begin(), d_vec2.end(), unary_op, 0.0f, binary_op)); + + // compute norm + re = (reduction/reduction2); + if (re < epsil) count++; + if (count > 3) break; + } } - if (printM == 1) printf("FGP-dTV iterations stopped at iteration %i \n", i); - /***************************************************************/ + /***************************************************************/ //copy result matrix from device to host memory cudaMemcpy(Output,d_update,ImSize*sizeof(float),cudaMemcpyDeviceToHost); - + cudaFree(d_input); cudaFree(d_update); if (epsil != 0.0f) cudaFree(d_update_prev); @@ -736,6 +748,10 @@ extern "C" int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, fl cudaFree(InputRef_z); cudaFree(d_InputRef); } - //cudaDeviceReset(); + + + /*adding info into info_vector */ + infovector[0] = (float)(i); /*iterations number (if stopped earlier based on tolerance)*/ + infovector[1] = re; /* reached tolerance */ return 0; } diff --git a/src/Core/regularisers_GPU/dTV_FGP_GPU_core.h b/src/Core/regularisers_GPU/dTV_FGP_GPU_core.h index f9281e8..4a1b16b 100644 --- a/src/Core/regularisers_GPU/dTV_FGP_GPU_core.h +++ b/src/Core/regularisers_GPU/dTV_FGP_GPU_core.h @@ -4,6 +4,6 @@ #include "CCPiDefines.h" #include <memory.h> -extern "C" CCPI_EXPORT int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, float lambdaPar, int iter, float epsil, float eta, int methodTV, int nonneg, int printM, int dimX, int dimY, int dimZ); +extern "C" CCPI_EXPORT int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, float *infovector, float lambdaPar, int iter, float epsil, float eta, int methodTV, int nonneg, int dimX, int dimY, int dimZ); -#endif +#endif diff --git a/src/Matlab/mex_compile/compileCPU_mex_Linux.m b/src/Matlab/mex_compile/compileCPU_mex_Linux.m index f3d9ce1..d8035f4 100644 --- a/src/Matlab/mex_compile/compileCPU_mex_Linux.m +++ b/src/Matlab/mex_compile/compileCPU_mex_Linux.m @@ -11,7 +11,7 @@ copyfile(pathcopyFrom1, 'regularisers_CPU'); copyfile(pathcopyFrom2, 'regularisers_CPU'); cd regularisers_CPU - +%% Pathmove = sprintf(['..' fsep 'installed' fsep], 1i); fprintf('%s \n', '<<<<<<<<<<<Compiling CPU regularisers>>>>>>>>>>>>>'); @@ -27,56 +27,55 @@ movefile('FGP_TV.mex*',Pathmove); fprintf('%s \n', 'Compiling SB-TV...'); mex SB_TV.c SB_TV_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" movefile('SB_TV.mex*',Pathmove); - -fprintf('%s \n', 'Compiling dFGP-TV...'); -mex FGP_dTV.c FGP_dTV_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -movefile('FGP_dTV.mex*',Pathmove); - -fprintf('%s \n', 'Compiling TNV...'); -mex TNV.c TNV_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -movefile('TNV.mex*',Pathmove); - -fprintf('%s \n', 'Compiling NonLinear Diffusion...'); -mex NonlDiff.c Diffusion_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -movefile('NonlDiff.mex*',Pathmove); - -fprintf('%s \n', 'Compiling Anisotropic diffusion of higher order...'); -mex Diffusion_4thO.c Diffus4th_order_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -movefile('Diffusion_4thO.mex*',Pathmove); - -fprintf('%s \n', 'Compiling TGV...'); -mex TGV.c TGV_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -movefile('TGV.mex*',Pathmove); - -fprintf('%s \n', 'Compiling ROF-LLT...'); -mex LLT_ROF.c LLT_ROF_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -movefile('LLT_ROF.mex*',Pathmove); - -fprintf('%s \n', 'Compiling NonLocal-TV...'); -mex PatchSelect.c PatchSelect_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -mex Nonlocal_TV.c Nonlocal_TV_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -movefile('Nonlocal_TV.mex*',Pathmove); -movefile('PatchSelect.mex*',Pathmove); - -fprintf('%s \n', 'Compiling additional tools...'); -mex TV_energy.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -movefile('TV_energy.mex*',Pathmove); +% +% fprintf('%s \n', 'Compiling dFGP-TV...'); +% mex FGP_dTV.c FGP_dTV_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +% movefile('FGP_dTV.mex*',Pathmove); +% +% fprintf('%s \n', 'Compiling TNV...'); +% mex TNV.c TNV_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +% movefile('TNV.mex*',Pathmove); +% +% fprintf('%s \n', 'Compiling NonLinear Diffusion...'); +% mex NonlDiff.c Diffusion_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +% movefile('NonlDiff.mex*',Pathmove); +% +% fprintf('%s \n', 'Compiling Anisotropic diffusion of higher order...'); +% mex Diffusion_4thO.c Diffus4th_order_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +% movefile('Diffusion_4thO.mex*',Pathmove); +% +% fprintf('%s \n', 'Compiling TGV...'); +% mex TGV.c TGV_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +% movefile('TGV.mex*',Pathmove); +% +% fprintf('%s \n', 'Compiling ROF-LLT...'); +% mex LLT_ROF.c LLT_ROF_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +% movefile('LLT_ROF.mex*',Pathmove); +% +% fprintf('%s \n', 'Compiling NonLocal-TV...'); +% mex PatchSelect.c PatchSelect_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +% mex Nonlocal_TV.c Nonlocal_TV_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +% movefile('Nonlocal_TV.mex*',Pathmove); +% movefile('PatchSelect.mex*',Pathmove); +% +% fprintf('%s \n', 'Compiling additional tools...'); +% mex TV_energy.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +% movefile('TV_energy.mex*',Pathmove); %############Inpainters##############% -fprintf('%s \n', 'Compiling Nonlinear/Linear diffusion inpainting...'); -mex NonlDiff_Inp.c Diffusion_Inpaint_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -movefile('NonlDiff_Inp.mex*',Pathmove); - -fprintf('%s \n', 'Compiling Nonlocal marching method for inpainting...'); -mex NonlocalMarching_Inpaint.c NonlocalMarching_Inpaint_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" -movefile('NonlocalMarching_Inpaint.mex*',Pathmove); - +% fprintf('%s \n', 'Compiling Nonlinear/Linear diffusion inpainting...'); +% mex NonlDiff_Inp.c Diffusion_Inpaint_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +% movefile('NonlDiff_Inp.mex*',Pathmove); +% +% fprintf('%s \n', 'Compiling Nonlocal marching method for inpainting...'); +% mex NonlocalMarching_Inpaint.c NonlocalMarching_Inpaint_core.c utils.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp" +% movefile('NonlocalMarching_Inpaint.mex*',Pathmove); +% delete SB_TV_core* ROF_TV_core* FGP_TV_core* FGP_dTV_core* TNV_core* utils* Diffusion_core* Diffus4th_order_core* TGV_core* LLT_ROF_core* CCPiDefines.h delete PatchSelect_core* Nonlocal_TV_core* delete Diffusion_Inpaint_core* NonlocalMarching_Inpaint_core* fprintf('%s \n', '<<<<<<< Regularisers successfully compiled! >>>>>>>'); -%pathA2 = sprintf(['..' fsep '..' fsep], 1i); -% cd(pathA2); -cd('/home/kjy41806/Documents/SOFT/CCPi-Regularisation-Toolkit/demos') -%cd demos +pathA2 = sprintf(['..' fsep '..' fsep '..' fsep '..' fsep 'demos'], 1i); +cd(pathA2); + diff --git a/src/Matlab/mex_compile/regularisers_CPU/FGP_TV.c b/src/Matlab/mex_compile/regularisers_CPU/FGP_TV.c index 603e0f4..f160b15 100644 --- a/src/Matlab/mex_compile/regularisers_CPU/FGP_TV.c +++ b/src/Matlab/mex_compile/regularisers_CPU/FGP_TV.c @@ -29,10 +29,10 @@ * 4. eplsilon: tolerance constant * 5. TV-type: methodTV - 'iso' (0) or 'l1' (1) * 6. nonneg: 'nonnegativity (0 is OFF by default) - * 7. print information: 0 (off) or 1 (on) * * Output: * [1] Filtered/regularized image + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the Matlab's code and paper by * [1] Amir Beck and Marc Teboulle, "Fast Gradient-Based Algorithms for Constrained Total Variation Image Denoising and Deblurring Problems" @@ -44,10 +44,10 @@ void mexFunction( int nrhs, const mxArray *prhs[]) { - int number_of_dims, iter, methTV, printswitch, nonneg; + int number_of_dims, iter, methTV, nonneg; mwSize dimX, dimY, dimZ; const mwSize *dim_array; - float *Input, *Output=NULL, *Output2=NULL, lambda, epsil; + float *Input, *infovec=NULL, *Output=NULL, lambda, epsil; number_of_dims = mxGetNumberOfDimensions(prhs[0]); dim_array = mxGetDimensions(prhs[0]); @@ -57,11 +57,10 @@ void mexFunction( Input = (float *) mxGetData(prhs[0]); /*noisy image (2D/3D) */ lambda = (float) mxGetScalar(prhs[1]); /* regularization parameter */ - iter = 300; /* default iterations number */ - epsil = 0.0001; /* default tolerance constant */ + iter = 400; /* default iterations number */ + epsil = 0.0; /* default tolerance constant */ methTV = 0; /* default isotropic TV penalty */ nonneg = 0; /* default nonnegativity switch, off - 0 */ -// printswitch = 0; /*default print is switched, off - 0 */ if (mxGetClassID(prhs[0]) != mxSINGLE_CLASS) {mexErrMsgTxt("The input image must be in a single precision"); } @@ -81,17 +80,19 @@ void mexFunction( /*Handling Matlab output data*/ - dimX = dim_array[0]; dimY = dim_array[1]; dimZ = dim_array[2]; - + dimX = dim_array[0]; dimY = dim_array[1]; dimZ = dim_array[2]; + if (number_of_dims == 2) { dimZ = 1; /*2D case*/ - Output = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); - Output2 = (float*)mxGetPr(plhs[1] = mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); + Output = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); } if (number_of_dims == 3) { - Output = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); - } + Output = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); + } + int vecdim[1]; + vecdim[0] = 2; + infovec = (float*)mxGetPr(plhs[1] = mxCreateNumericArray(1, vecdim, mxSINGLE_CLASS, mxREAL)); /* running the function */ - TV_FGP_CPU_main(Input, Output, Output2, lambda, iter, epsil, methTV, nonneg, dimX, dimY, dimZ); + TV_FGP_CPU_main(Input, Output, infovec, lambda, iter, epsil, methTV, nonneg, dimX, dimY, dimZ); } diff --git a/src/Matlab/mex_compile/regularisers_CPU/ROF_TV.c b/src/Matlab/mex_compile/regularisers_CPU/ROF_TV.c index 55ef2b1..a7d431f 100644 --- a/src/Matlab/mex_compile/regularisers_CPU/ROF_TV.c +++ b/src/Matlab/mex_compile/regularisers_CPU/ROF_TV.c @@ -29,9 +29,11 @@ * 2. lambda - regularization parameter [REQUIRED] * 3. Number of iterations, for explicit scheme >= 150 is recommended [REQUIRED] * 4. tau - marching step for explicit scheme, ~1 is recommended [REQUIRED] + * 5. eplsilon: tolerance constant [REQUIRED] * * Output: * [1] Regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the paper by * [1] Rudin, Osher, Fatemi, "Nonlinear Total Variation based noise removal algorithms" @@ -47,7 +49,8 @@ void mexFunction( int number_of_dims, iter_numb; mwSize dimX, dimY, dimZ; const mwSize *dim_array_i; - float *Input, *Output=NULL, lambda, tau; + float *Input, *Output=NULL, lambda, tau, epsil; + float *infovec=NULL; dim_array_i = mxGetDimensions(prhs[0]); number_of_dims = mxGetNumberOfDimensions(prhs[0]); @@ -57,9 +60,10 @@ void mexFunction( lambda = (float) mxGetScalar(prhs[1]); /* regularization parameter */ iter_numb = (int) mxGetScalar(prhs[2]); /* iterations number */ tau = (float) mxGetScalar(prhs[3]); /* marching step parameter */ + epsil = (float) mxGetScalar(prhs[4]); /* tolerance */ if (mxGetClassID(prhs[0]) != mxSINGLE_CLASS) {mexErrMsgTxt("The input image must be in a single precision"); } - if(nrhs != 4) mexErrMsgTxt("Four inputs reqired: Image(2D,3D), regularization parameter, iterations number, marching step constant"); + if(nrhs != 5) mexErrMsgTxt("Four inputs reqired: Image(2D,3D), regularization parameter, iterations number, marching step constant, tolerance"); /*Handling Matlab output data*/ dimX = dim_array_i[0]; dimY = dim_array_i[1]; dimZ = dim_array_i[2]; @@ -72,6 +76,10 @@ void mexFunction( if (number_of_dims == 3) { Output = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(3, dim_array_i, mxSINGLE_CLASS, mxREAL)); } + + int vecdim[1]; + vecdim[0] = 2; + infovec = (float*)mxGetPr(plhs[1] = mxCreateNumericArray(1, vecdim, mxSINGLE_CLASS, mxREAL)); - TV_ROF_CPU_main(Input, Output, lambda, iter_numb, tau, dimX, dimY, dimZ); + TV_ROF_CPU_main(Input, Output, infovec, lambda, iter_numb, tau, epsil, dimX, dimY, dimZ); }
\ No newline at end of file diff --git a/src/Matlab/mex_compile/regularisers_CPU/SB_TV.c b/src/Matlab/mex_compile/regularisers_CPU/SB_TV.c index 8636322..495f1c9 100644 --- a/src/Matlab/mex_compile/regularisers_CPU/SB_TV.c +++ b/src/Matlab/mex_compile/regularisers_CPU/SB_TV.c @@ -28,10 +28,10 @@ * 3. Number of iterations [OPTIONAL parameter] * 4. eplsilon - tolerance constant [OPTIONAL parameter] * 5. TV-type: 'iso' or 'l1' [OPTIONAL parameter] -* 6. print information: 0 (off) or 1 (on) [OPTIONAL parameter] * -* Output: -* 1. Filtered/regularized image + * Output: + * [1] Regularized image/volume + * [2] Information vector which contains [iteration no., reached tolerance] * * This function is based on the Matlab's code and paper by * [1]. Goldstein, T. and Osher, S., 2009. The split Bregman method for L1-regularized problems. SIAM journal on imaging sciences, 2(2), pp.323-343. @@ -42,40 +42,36 @@ void mexFunction( int nrhs, const mxArray *prhs[]) { - int number_of_dims, iter, methTV, printswitch; + int number_of_dims, iter, methTV; mwSize dimX, dimY, dimZ; const mwSize *dim_array; float *Input, *Output=NULL, lambda, epsil; + float *infovec=NULL; number_of_dims = mxGetNumberOfDimensions(prhs[0]); dim_array = mxGetDimensions(prhs[0]); /*Handling Matlab input data*/ - if ((nrhs < 2) || (nrhs > 6)) mexErrMsgTxt("At least 2 parameters is required, all parameters are: Image(2D/3D), Regularization parameter, Regularization parameter, iterations number, tolerance, penalty type ('iso' or 'l1'), print switch"); + if ((nrhs < 2) || (nrhs > 5)) mexErrMsgTxt("At least 2 parameters is required, all parameters are: Image(2D/3D), Regularisation parameter,iterations number, tolerance, penalty type ('iso' or 'l1')"); Input = (float *) mxGetData(prhs[0]); /*noisy image (2D/3D) */ lambda = (float) mxGetScalar(prhs[1]); /* regularization parameter */ - iter = 100; /* default iterations number */ - epsil = 0.0001; /* default tolerance constant */ + iter = 200; /* default iterations number */ + epsil = 1.0e-06; /* default tolerance constant */ methTV = 0; /* default isotropic TV penalty */ - printswitch = 0; /*default print is switched, off - 0 */ if (mxGetClassID(prhs[0]) != mxSINGLE_CLASS) {mexErrMsgTxt("The input image must be in a single precision"); } - if ((nrhs == 3) || (nrhs == 4) || (nrhs == 5) || (nrhs == 6)) iter = (int) mxGetScalar(prhs[2]); /* iterations number */ - if ((nrhs == 4) || (nrhs == 5) || (nrhs == 6)) epsil = (float) mxGetScalar(prhs[3]); /* tolerance constant */ - if ((nrhs == 5) || (nrhs == 6)) { + if ((nrhs == 3) || (nrhs == 4) || (nrhs == 5)) iter = (int) mxGetScalar(prhs[2]); /* iterations number */ + if ((nrhs == 4) || (nrhs == 5)) epsil = (float) mxGetScalar(prhs[3]); /* tolerance constant */ + if ((nrhs == 5)) { char *penalty_type; penalty_type = mxArrayToString(prhs[4]); /* choosing TV penalty: 'iso' or 'l1', 'iso' is the default */ if ((strcmp(penalty_type, "l1") != 0) && (strcmp(penalty_type, "iso") != 0)) mexErrMsgTxt("Choose TV type: 'iso' or 'l1',"); if (strcmp(penalty_type, "l1") == 0) methTV = 1; /* enable 'l1' penalty */ mxFree(penalty_type); } - if (nrhs == 6) { - printswitch = (int) mxGetScalar(prhs[5]); - if ((printswitch != 0) && (printswitch != 1)) mexErrMsgTxt("Print can be enabled by choosing 1 or off - 0"); - } /*Handling Matlab output data*/ dimX = dim_array[0]; dimY = dim_array[1]; dimZ = dim_array[2]; @@ -86,6 +82,10 @@ void mexFunction( } if (number_of_dims == 3) Output = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL)); + int vecdim[1]; + vecdim[0] = 2; + infovec = (float*)mxGetPr(plhs[1] = mxCreateNumericArray(1, vecdim, mxSINGLE_CLASS, mxREAL)); + /* running the function */ - SB_TV_CPU_main(Input, Output, lambda, iter, epsil, methTV, printswitch, dimX, dimY, dimZ); + SB_TV_CPU_main(Input, Output, infovec, lambda, iter, epsil, methTV, dimX, dimY, dimZ); } diff --git a/src/Python/ccpi/filters/regularisers.py b/src/Python/ccpi/filters/regularisers.py index 09b465a..398e11c 100644 --- a/src/Python/ccpi/filters/regularisers.py +++ b/src/Python/ccpi/filters/regularisers.py @@ -7,7 +7,7 @@ try: from ccpi.filters.gpu_regularisers import TV_ROF_GPU, TV_FGP_GPU, TV_SB_GPU, dTV_FGP_GPU, NDF_GPU, Diff4th_GPU, TGV_GPU, LLT_ROF_GPU, PATCHSEL_GPU gpu_enabled = True except ImportError: - gpu_enabled = False + gpu_enabled = False from ccpi.filters.cpu_regularisers import NDF_INPAINT_CPU, NVM_INPAINT_CPU def ROF_TV(inputData, regularisation_parameter, iterations, @@ -15,13 +15,13 @@ def ROF_TV(inputData, regularisation_parameter, iterations, if device == 'cpu': return TV_ROF_CPU(inputData, regularisation_parameter, - iterations, + iterations, time_marching_parameter, tolerance_param) elif device == 'gpu' and gpu_enabled: return TV_ROF_GPU(inputData, regularisation_parameter, - iterations, + iterations, time_marching_parameter, tolerance_param) else: @@ -35,14 +35,14 @@ def FGP_TV(inputData, regularisation_parameter,iterations, if device == 'cpu': return TV_FGP_CPU(inputData, regularisation_parameter, - iterations, + iterations, tolerance_param, methodTV, nonneg) elif device == 'gpu' and gpu_enabled: return TV_FGP_GPU(inputData, regularisation_parameter, - iterations, + iterations, tolerance_param, methodTV, nonneg) @@ -56,13 +56,13 @@ def SB_TV(inputData, regularisation_parameter, iterations, if device == 'cpu': return TV_SB_CPU(inputData, regularisation_parameter, - iterations, + iterations, tolerance_param, methodTV) elif device == 'gpu' and gpu_enabled: return TV_SB_GPU(inputData, regularisation_parameter, - iterations, + iterations, tolerance_param, methodTV) else: @@ -81,91 +81,115 @@ def LLT_ROF(inputData, regularisation_parameterROF, regularisation_parameterLLT, raise ValueError ('GPU is not available') raise ValueError('Unknown device {0}. Expecting gpu or cpu'\ .format(device)) -def FGP_dTV(inputData, refdata, regularisation_parameter, iterations, - tolerance_param, eta_const, methodTV, nonneg, printM, device='cpu'): +def TGV(inputData, regularisation_parameter, alpha1, alpha0, iterations, + LipshitzConst, tolerance_param, device='cpu'): if device == 'cpu': - return dTV_FGP_CPU(inputData, - refdata, - regularisation_parameter, - iterations, - tolerance_param, - eta_const, - methodTV, - nonneg, - printM) + return TGV_CPU(inputData, + regularisation_parameter, + alpha1, + alpha0, + iterations, + LipshitzConst, + tolerance_param) elif device == 'gpu' and gpu_enabled: - return dTV_FGP_GPU(inputData, - refdata, - regularisation_parameter, - iterations, - tolerance_param, - eta_const, - methodTV, - nonneg, - printM) + return TGV_GPU(inputData, + regularisation_parameter, + alpha1, + alpha0, + iterations, + LipshitzConst, + tolerance_param) else: if not gpu_enabled and device == 'gpu': raise ValueError ('GPU is not available') raise ValueError('Unknown device {0}. Expecting gpu or cpu'\ .format(device)) -def TNV(inputData, regularisation_parameter, iterations, tolerance_param): - return TNV_CPU(inputData, - regularisation_parameter, - iterations, - tolerance_param) def NDF(inputData, regularisation_parameter, edge_parameter, iterations, - time_marching_parameter, penalty_type, device='cpu'): + time_marching_parameter, penalty_type, tolerance_param, device='cpu'): if device == 'cpu': return NDF_CPU(inputData, regularisation_parameter, edge_parameter, - iterations, + iterations, time_marching_parameter, - penalty_type) + penalty_type, + tolerance_param) elif device == 'gpu' and gpu_enabled: return NDF_GPU(inputData, regularisation_parameter, edge_parameter, - iterations, + iterations, time_marching_parameter, - penalty_type) + penalty_type, + tolerance_param) else: if not gpu_enabled and device == 'gpu': raise ValueError ('GPU is not available') raise ValueError('Unknown device {0}. Expecting gpu or cpu'\ .format(device)) def Diff4th(inputData, regularisation_parameter, edge_parameter, iterations, - time_marching_parameter, device='cpu'): + time_marching_parameter, tolerance_param, device='cpu'): if device == 'cpu': return Diff4th_CPU(inputData, regularisation_parameter, edge_parameter, - iterations, - time_marching_parameter) + iterations, + time_marching_parameter, + tolerance_param) elif device == 'gpu' and gpu_enabled: return Diff4th_GPU(inputData, regularisation_parameter, edge_parameter, - iterations, - time_marching_parameter) + iterations, + time_marching_parameter, + tolerance_param) else: if not gpu_enabled and device == 'gpu': raise ValueError ('GPU is not available') raise ValueError('Unknown device {0}. Expecting gpu or cpu'\ .format(device)) - +def FGP_dTV(inputData, refdata, regularisation_parameter, iterations, + tolerance_param, eta_const, methodTV, nonneg, device='cpu'): + if device == 'cpu': + return dTV_FGP_CPU(inputData, + refdata, + regularisation_parameter, + iterations, + tolerance_param, + eta_const, + methodTV, + nonneg) + elif device == 'gpu' and gpu_enabled: + return dTV_FGP_GPU(inputData, + refdata, + regularisation_parameter, + iterations, + tolerance_param, + eta_const, + methodTV, + nonneg) + else: + if not gpu_enabled and device == 'gpu': + raise ValueError ('GPU is not available') + raise ValueError('Unknown device {0}. Expecting gpu or cpu'\ + .format(device)) +def TNV(inputData, regularisation_parameter, iterations, tolerance_param): + return TNV_CPU(inputData, + regularisation_parameter, + iterations, + tolerance_param) def PatchSelect(inputData, searchwindow, patchwindow, neighbours, edge_parameter, device='cpu'): if device == 'cpu': return PATCHSEL_CPU(inputData, searchwindow, patchwindow, - neighbours, + neighbours, edge_parameter) elif device == 'gpu' and gpu_enabled: return PATCHSEL_GPU(inputData, searchwindow, patchwindow, - neighbours, + neighbours, edge_parameter) else: if not gpu_enabled and device == 'gpu': @@ -177,36 +201,14 @@ def NLTV(inputData, H_i, H_j, H_k, Weights, regularisation_parameter, iterations return NLTV_CPU(inputData, H_i, H_j, - H_k, + H_k, Weights, regularisation_parameter, iterations) - -def TGV(inputData, regularisation_parameter, alpha1, alpha0, iterations, - LipshitzConst, device='cpu'): - if device == 'cpu': - return TGV_CPU(inputData, - regularisation_parameter, - alpha1, - alpha0, - iterations, - LipshitzConst) - elif device == 'gpu' and gpu_enabled: - return TGV_GPU(inputData, - regularisation_parameter, - alpha1, - alpha0, - iterations, - LipshitzConst) - else: - if not gpu_enabled and device == 'gpu': - raise ValueError ('GPU is not available') - raise ValueError('Unknown device {0}. Expecting gpu or cpu'\ - .format(device)) def NDF_INP(inputData, maskData, regularisation_parameter, edge_parameter, iterations, time_marching_parameter, penalty_type): - return NDF_INPAINT_CPU(inputData, maskData, regularisation_parameter, + return NDF_INPAINT_CPU(inputData, maskData, regularisation_parameter, edge_parameter, iterations, time_marching_parameter, penalty_type) - + def NVM_INP(inputData, maskData, SW_increment, iterations): return NVM_INPAINT_CPU(inputData, maskData, SW_increment, iterations) diff --git a/src/Python/src/cpu_regularisers.pyx b/src/Python/src/cpu_regularisers.pyx index f2276bb..add641b 100644 --- a/src/Python/src/cpu_regularisers.pyx +++ b/src/Python/src/cpu_regularisers.pyx @@ -22,11 +22,11 @@ cdef extern float TV_ROF_CPU_main(float *Input, float *Output, float *infovector cdef extern float TV_FGP_CPU_main(float *Input, float *Output, float *infovector, float lambdaPar, int iterationsNumb, float epsil, int methodTV, int nonneg, int dimX, int dimY, int dimZ); cdef extern float SB_TV_CPU_main(float *Input, float *Output, float *infovector, float mu, int iter, float epsil, int methodTV, int dimX, int dimY, int dimZ); cdef extern float LLT_ROF_CPU_main(float *Input, float *Output, float *infovector, float lambdaROF, float lambdaLLT, int iterationsNumb, float tau, float epsil, int dimX, int dimY, int dimZ); -cdef extern float TGV_main(float *Input, float *Output, float lambdaPar, float alpha1, float alpha0, int iterationsNumb, float L2, int dimX, int dimY, int dimZ); -cdef extern float Diffusion_CPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, int dimX, int dimY, int dimZ); -cdef extern float Diffus4th_CPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int dimX, int dimY, int dimZ); +cdef extern float TGV_main(float *Input, float *Output, float *infovector, float lambdaPar, float alpha1, float alpha0, int iterationsNumb, float L2, float epsil, int dimX, int dimY, int dimZ); +cdef extern float Diffusion_CPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, float epsil, int dimX, int dimY, int dimZ); +cdef extern float Diffus4th_CPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, float epsil, int dimX, int dimY, int dimZ); +cdef extern float dTV_FGP_CPU_main(float *Input, float *InputRef, float *Output, float *infovector, float lambdaPar, int iterationsNumb, float epsil, float eta, int methodTV, int nonneg, int dimX, int dimY, int dimZ); cdef extern float TNV_CPU_main(float *Input, float *u, float lambdaPar, int maxIter, float tol, int dimX, int dimY, int dimZ); -cdef extern float dTV_FGP_CPU_main(float *Input, float *InputRef, float *Output, float lambdaPar, int iterationsNumb, float epsil, float eta, int methodTV, int nonneg, int printM, int dimX, int dimY, int dimZ); cdef extern float PatchSelect_CPU_main(float *Input, unsigned short *H_i, unsigned short *H_j, unsigned short *H_k, float *Weights, int dimX, int dimY, int dimZ, int SearchWindow, int SimilarWin, int NumNeighb, float h, int switchM); cdef extern float Nonlocal_TV_CPU_main(float *A_orig, float *Output, unsigned short *H_i, unsigned short *H_j, unsigned short *H_k, float *Weights, int dimX, int dimY, int dimZ, int NumNeighb, float lambdaReg, int IterNumb); @@ -43,7 +43,7 @@ def TV_ROF_CPU(inputData, regularisation_parameter, iterationsNumb, marching_ste elif inputData.ndim == 3: return TV_ROF_3D(inputData, regularisation_parameter, iterationsNumb, marching_step_parameter,tolerance_param) -def TV_ROF_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def TV_ROF_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameter, int iterationsNumb, float marching_step_parameter, @@ -51,18 +51,18 @@ def TV_ROF_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ np.zeros([dims[0],dims[1]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.ones([2], dtype='float32') - - # Run ROF iterations for 2D data + + # Run ROF iterations for 2D data TV_ROF_CPU_main(&inputData[0,0], &outputData[0,0], &infovec[0], regularisation_parameter, iterationsNumb, marching_step_parameter, tolerance_param, dims[1], dims[0], 1) - + return (outputData,infovec) - -def TV_ROF_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + +def TV_ROF_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, int iterationsNumb, float marching_step_parameter, @@ -71,13 +71,13 @@ def TV_ROF_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ np.zeros([dims[0],dims[1],dims[2]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.ones([2], dtype='float32') - - # Run ROF iterations for 3D data + + # Run ROF iterations for 3D data TV_ROF_CPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], regularisation_parameter, iterationsNumb, marching_step_parameter, tolerance_param, dims[2], dims[1], dims[0]) return (outputData,infovec) @@ -92,9 +92,9 @@ def TV_FGP_CPU(inputData, regularisation_parameter, iterationsNumb, tolerance_pa elif inputData.ndim == 3: return TV_FGP_3D(inputData, regularisation_parameter, iterationsNumb, tolerance_param, methodTV, nonneg) -def TV_FGP_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def TV_FGP_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameter, - int iterationsNumb, + int iterationsNumb, float tolerance_param, int methodTV, int nonneg): @@ -102,35 +102,35 @@ def TV_FGP_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ np.zeros([dims[0],dims[1]], dtype='float32') - + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.ones([2], dtype='float32') - + #/* Run FGP-TV iterations for 2D data */ - TV_FGP_CPU_main(&inputData[0,0], &outputData[0,0], &infovec[0], regularisation_parameter, - iterationsNumb, + TV_FGP_CPU_main(&inputData[0,0], &outputData[0,0], &infovec[0], regularisation_parameter, + iterationsNumb, tolerance_param, methodTV, nonneg, dims[1],dims[0],1) - + return (outputData,infovec) - -def TV_FGP_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + +def TV_FGP_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, - int iterationsNumb, + int iterationsNumb, float tolerance_param, int methodTV, int nonneg): - + cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ np.zeros([dims[0], dims[1], dims[2]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ @@ -138,7 +138,7 @@ def TV_FGP_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, #/* Run FGP-TV iterations for 3D data */ TV_FGP_CPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], regularisation_parameter, - iterationsNumb, + iterationsNumb, tolerance_param, methodTV, nonneg, @@ -155,54 +155,54 @@ def TV_SB_CPU(inputData, regularisation_parameter, iterationsNumb, tolerance_par elif inputData.ndim == 3: return TV_SB_3D(inputData, regularisation_parameter, iterationsNumb, tolerance_param, methodTV) -def TV_SB_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def TV_SB_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameter, - int iterationsNumb, + int iterationsNumb, float tolerance_param, int methodTV): - + cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ np.zeros([dims[0],dims[1]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.zeros([2], dtype='float32') - + #/* Run SB-TV iterations for 2D data */ SB_TV_CPU_main(&inputData[0,0], &outputData[0,0], &infovec[0], - regularisation_parameter, - iterationsNumb, + regularisation_parameter, + iterationsNumb, tolerance_param, methodTV, dims[1],dims[0], 1) - + return (outputData,infovec) - -def TV_SB_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + +def TV_SB_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, - int iterationsNumb, + int iterationsNumb, float tolerance_param, int methodTV): cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ np.zeros([dims[0], dims[1], dims[2]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.zeros([2], dtype='float32') - + #/* Run SB-TV iterations for 3D data */ SB_TV_CPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], regularisation_parameter, - iterationsNumb, + iterationsNumb, tolerance_param, methodTV, dims[2], dims[1], dims[0]) - return (outputData,infovec) + return (outputData,infovec) #***************************************************************# #******************* ROF - LLT regularisation ******************# #***************************************************************# @@ -212,288 +212,321 @@ def LLT_ROF_CPU(inputData, regularisation_parameterROF, regularisation_parameter elif inputData.ndim == 3: return LLT_ROF_3D(inputData, regularisation_parameterROF, regularisation_parameterLLT, iterations, time_marching_parameter, tolerance_param) -def LLT_ROF_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def LLT_ROF_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameterROF, float regularisation_parameterLLT, - int iterations, + int iterations, float time_marching_parameter, float tolerance_param): - + cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ np.zeros([dims[0],dims[1]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.zeros([2], dtype='float32') - + #/* Run ROF-LLT iterations for 2D data */ - LLT_ROF_CPU_main(&inputData[0,0], &outputData[0,0], &infovec[0], regularisation_parameterROF, regularisation_parameterLLT, iterations, time_marching_parameter, + LLT_ROF_CPU_main(&inputData[0,0], &outputData[0,0], &infovec[0], regularisation_parameterROF, regularisation_parameterLLT, iterations, time_marching_parameter, tolerance_param, dims[1],dims[0],1) - return (outputData,infovec) + return (outputData,infovec) -def LLT_ROF_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, +def LLT_ROF_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameterROF, float regularisation_parameterLLT, - int iterations, + int iterations, float time_marching_parameter, float tolerance_param): - + cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ np.zeros([dims[0], dims[1], dims[2]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.zeros([2], dtype='float32') - + #/* Run ROF-LLT iterations for 3D data */ - LLT_ROF_CPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], regularisation_parameterROF, regularisation_parameterLLT, iterations, + LLT_ROF_CPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], regularisation_parameterROF, regularisation_parameterLLT, iterations, time_marching_parameter, - tolerance_param, + tolerance_param, dims[2], dims[1], dims[0]) return (outputData,infovec) #***************************************************************# #***************** Total Generalised Variation *****************# #***************************************************************# -def TGV_CPU(inputData, regularisation_parameter, alpha1, alpha0, iterations, LipshitzConst): +def TGV_CPU(inputData, regularisation_parameter, alpha1, alpha0, iterations, LipshitzConst, tolerance_param): if inputData.ndim == 2: - return TGV_2D(inputData, regularisation_parameter, alpha1, alpha0, - iterations, LipshitzConst) + return TGV_2D(inputData, regularisation_parameter, alpha1, alpha0, + iterations, LipshitzConst, tolerance_param) elif inputData.ndim == 3: - return TGV_3D(inputData, regularisation_parameter, alpha1, alpha0, - iterations, LipshitzConst) + return TGV_3D(inputData, regularisation_parameter, alpha1, alpha0, + iterations, LipshitzConst, tolerance_param) -def TGV_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def TGV_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameter, float alpha1, float alpha0, - int iterationsNumb, - float LipshitzConst): - + int iterationsNumb, + float LipshitzConst, + float tolerance_param): + cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ np.zeros([dims[0],dims[1]], dtype='float32') - + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.zeros([2], dtype='float32') + #/* Run TGV iterations for 2D data */ - TGV_main(&inputData[0,0], &outputData[0,0], regularisation_parameter, + TGV_main(&inputData[0,0], &outputData[0,0], &infovec[0], regularisation_parameter, alpha1, alpha0, - iterationsNumb, + iterationsNumb, LipshitzConst, + tolerance_param, dims[1],dims[0],1) - return outputData -def TGV_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + return (outputData,infovec) +def TGV_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, float alpha1, float alpha0, - int iterationsNumb, - float LipshitzConst): - + int iterationsNumb, + float LipshitzConst, + float tolerance_param): + cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ np.zeros([dims[0], dims[1], dims[2]], dtype='float32') - + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.zeros([2], dtype='float32') + #/* Run TGV iterations for 3D data */ - TGV_main(&inputData[0,0,0], &outputData[0,0,0], regularisation_parameter, + TGV_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], regularisation_parameter, alpha1, alpha0, - iterationsNumb, + iterationsNumb, LipshitzConst, + tolerance_param, dims[2], dims[1], dims[0]) - return outputData - + return (outputData,infovec) #****************************************************************# -#**************Directional Total-variation FGP ******************# +#***************Nonlinear (Isotropic) Diffusion******************# #****************************************************************# -#******** Directional TV Fast-Gradient-Projection (FGP)*********# -def dTV_FGP_CPU(inputData, refdata, regularisation_parameter, iterationsNumb, tolerance_param, eta_const, methodTV, nonneg, printM): +def NDF_CPU(inputData, regularisation_parameter, edge_parameter, iterationsNumb,time_marching_parameter, penalty_type,tolerance_param): if inputData.ndim == 2: - return dTV_FGP_2D(inputData, refdata, regularisation_parameter, iterationsNumb, tolerance_param, eta_const, methodTV, nonneg, printM) + return NDF_2D(inputData, regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, penalty_type, tolerance_param) elif inputData.ndim == 3: - return dTV_FGP_3D(inputData, refdata, regularisation_parameter, iterationsNumb, tolerance_param, eta_const, methodTV, nonneg, printM) + return NDF_3D(inputData, regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, penalty_type, tolerance_param) -def dTV_FGP_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, - np.ndarray[np.float32_t, ndim=2, mode="c"] refdata, +def NDF_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameter, - int iterationsNumb, - float tolerance_param, - float eta_const, - int methodTV, - int nonneg, - int printM): - + float edge_parameter, + int iterationsNumb, + float time_marching_parameter, + int penalty_type, + float tolerance_param): cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ np.zeros([dims[0],dims[1]], dtype='float32') - - #/* Run FGP-dTV iterations for 2D data */ - dTV_FGP_CPU_main(&inputData[0,0], &refdata[0,0], &outputData[0,0], regularisation_parameter, - iterationsNumb, - tolerance_param, - eta_const, - methodTV, - nonneg, - printM, - dims[1], dims[0], 1) - - return outputData - -def dTV_FGP_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, - np.ndarray[np.float32_t, ndim=3, mode="c"] refdata, + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.zeros([2], dtype='float32') + + # Run Nonlinear Diffusion iterations for 2D data + Diffusion_CPU_main(&inputData[0,0], &outputData[0,0], &infovec[0], + regularisation_parameter, edge_parameter, iterationsNumb, + time_marching_parameter, penalty_type, + tolerance_param, + dims[1], dims[0], 1) + return (outputData,infovec) + +def NDF_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, - int iterationsNumb, - float tolerance_param, - float eta_const, - int methodTV, - int nonneg, - int printM): + float edge_parameter, + int iterationsNumb, + float time_marching_parameter, + int penalty_type, + float tolerance_param): cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ - np.zeros([dims[0], dims[1], dims[2]], dtype='float32') - - #/* Run FGP-dTV iterations for 3D data */ - dTV_FGP_CPU_main(&inputData[0,0,0], &refdata[0,0,0], &outputData[0,0,0], regularisation_parameter, - iterationsNumb, - tolerance_param, - eta_const, - methodTV, - nonneg, - printM, - dims[2], dims[1], dims[0]) - return outputData - + np.zeros([dims[0],dims[1],dims[2]], dtype='float32') + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.zeros([2], dtype='float32') + + # Run Nonlinear Diffusion iterations for 3D data + Diffusion_CPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], + regularisation_parameter, edge_parameter, iterationsNumb, + time_marching_parameter, penalty_type, + tolerance_param, + dims[2], dims[1], dims[0]) + return (outputData,infovec) #****************************************************************# -#*********************Total Nuclear Variation********************# +#*************Anisotropic Fourth-Order diffusion*****************# #****************************************************************# -def TNV_CPU(inputData, regularisation_parameter, iterationsNumb, tolerance_param): +def Diff4th_CPU(inputData, regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter,tolerance_param): if inputData.ndim == 2: - return + return Diff4th_2D(inputData, regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter,tolerance_param) elif inputData.ndim == 3: - return TNV_3D(inputData, regularisation_parameter, iterationsNumb, tolerance_param) + return Diff4th_3D(inputData, regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter,tolerance_param) + +def Diff4th_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, + float regularisation_parameter, + float edge_parameter, + int iterationsNumb, + float time_marching_parameter, + float tolerance_param): + cdef long dims[2] + dims[0] = inputData.shape[0] + dims[1] = inputData.shape[1] -def TNV_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ + np.zeros([dims[0],dims[1]], dtype='float32') + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.zeros([2], dtype='float32') + + # Run Anisotropic Fourth-Order diffusion for 2D data + Diffus4th_CPU_main(&inputData[0,0], &outputData[0,0], &infovec[0], + regularisation_parameter, + edge_parameter, iterationsNumb, + time_marching_parameter, + tolerance_param, + dims[1], dims[0], 1) + return (outputData,infovec) + +def Diff4th_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, + float edge_parameter, int iterationsNumb, + float time_marching_parameter, float tolerance_param): cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ np.zeros([dims[0],dims[1],dims[2]], dtype='float32') - - # Run TNV iterations for 3D (X,Y,Channels) data - TNV_CPU_main(&inputData[0,0,0], &outputData[0,0,0], regularisation_parameter, iterationsNumb, tolerance_param, dims[2], dims[1], dims[0]) - return outputData + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.zeros([2], dtype='float32') + + # Run Anisotropic Fourth-Order diffusion for 3D data + Diffus4th_CPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], + regularisation_parameter, edge_parameter, + iterationsNumb, time_marching_parameter, + tolerance_param, + dims[2], dims[1], dims[0]) + return (outputData,infovec) #****************************************************************# -#***************Nonlinear (Isotropic) Diffusion******************# +#**************Directional Total-variation FGP ******************# #****************************************************************# -def NDF_CPU(inputData, regularisation_parameter, edge_parameter, iterationsNumb,time_marching_parameter, penalty_type): +#******** Directional TV Fast-Gradient-Projection (FGP)*********# +def dTV_FGP_CPU(inputData, refdata, regularisation_parameter, iterationsNumb, tolerance_param, eta_const, methodTV, nonneg): if inputData.ndim == 2: - return NDF_2D(inputData, regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, penalty_type) + return dTV_FGP_2D(inputData, refdata, regularisation_parameter, iterationsNumb, tolerance_param, eta_const, methodTV, nonneg) elif inputData.ndim == 3: - return NDF_3D(inputData, regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, penalty_type) + return dTV_FGP_3D(inputData, refdata, regularisation_parameter, iterationsNumb, tolerance_param, eta_const, methodTV, nonneg) -def NDF_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def dTV_FGP_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, + np.ndarray[np.float32_t, ndim=2, mode="c"] refdata, float regularisation_parameter, - float edge_parameter, - int iterationsNumb, - float time_marching_parameter, - int penalty_type): + int iterationsNumb, + float tolerance_param, + float eta_const, + int methodTV, + int nonneg): + cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ - np.zeros([dims[0],dims[1]], dtype='float32') - - # Run Nonlinear Diffusion iterations for 2D data - Diffusion_CPU_main(&inputData[0,0], &outputData[0,0], regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, penalty_type, dims[1], dims[0], 1) - return outputData - -def NDF_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + np.zeros([dims[0],dims[1]], dtype='float32') + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.zeros([2], dtype='float32') + + #/* Run FGP-dTV iterations for 2D data */ + dTV_FGP_CPU_main(&inputData[0,0], &refdata[0,0], &outputData[0,0], &infovec[0], + regularisation_parameter, + iterationsNumb, + tolerance_param, + eta_const, + methodTV, + nonneg, + dims[1], dims[0], 1) + return (outputData,infovec) + +def dTV_FGP_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + np.ndarray[np.float32_t, ndim=3, mode="c"] refdata, float regularisation_parameter, - float edge_parameter, - int iterationsNumb, - float time_marching_parameter, - int penalty_type): + int iterationsNumb, + float tolerance_param, + float eta_const, + int methodTV, + int nonneg): cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ - np.zeros([dims[0],dims[1],dims[2]], dtype='float32') - - # Run Nonlinear Diffusion iterations for 3D data - Diffusion_CPU_main(&inputData[0,0,0], &outputData[0,0,0], regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, penalty_type, dims[2], dims[1], dims[0]) + np.zeros([dims[0], dims[1], dims[2]], dtype='float32') + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.zeros([2], dtype='float32') - return outputData + #/* Run FGP-dTV iterations for 3D data */ + dTV_FGP_CPU_main(&inputData[0,0,0], &refdata[0,0,0], &outputData[0,0,0], &infovec[0], + regularisation_parameter, + iterationsNumb, + tolerance_param, + eta_const, + methodTV, + nonneg, + dims[2], dims[1], dims[0]) + return (outputData,infovec) #****************************************************************# -#*************Anisotropic Fourth-Order diffusion*****************# +#*********************Total Nuclear Variation********************# #****************************************************************# -def Diff4th_CPU(inputData, regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter): +def TNV_CPU(inputData, regularisation_parameter, iterationsNumb, tolerance_param): if inputData.ndim == 2: - return Diff4th_2D(inputData, regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter) + return elif inputData.ndim == 3: - return Diff4th_3D(inputData, regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter) + return TNV_3D(inputData, regularisation_parameter, iterationsNumb, tolerance_param) -def Diff4th_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def TNV_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, - float edge_parameter, - int iterationsNumb, - float time_marching_parameter): - cdef long dims[2] - dims[0] = inputData.shape[0] - dims[1] = inputData.shape[1] - - cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ - np.zeros([dims[0],dims[1]], dtype='float32') - - # Run Anisotropic Fourth-Order diffusion for 2D data - Diffus4th_CPU_main(&inputData[0,0], &outputData[0,0], regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, dims[1], dims[0], 1) - return outputData - -def Diff4th_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, - float regularisation_parameter, - float edge_parameter, int iterationsNumb, - float time_marching_parameter): + float tolerance_param): cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ np.zeros([dims[0],dims[1],dims[2]], dtype='float32') - - # Run Anisotropic Fourth-Order diffusion for 3D data - Diffus4th_CPU_main(&inputData[0,0,0], &outputData[0,0,0], regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, dims[2], dims[1], dims[0]) + # Run TNV iterations for 3D (X,Y,Channels) data + TNV_CPU_main(&inputData[0,0,0], &outputData[0,0,0], regularisation_parameter, iterationsNumb, tolerance_param, dims[2], dims[1], dims[0]) return outputData - #****************************************************************# #***************Patch-based weights calculation******************# #****************************************************************# @@ -511,14 +544,14 @@ def PatchSel_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, dims[0] = neighbours dims[1] = inputData.shape[0] dims[2] = inputData.shape[1] - - + + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] Weights = \ np.zeros([dims[0], dims[1],dims[2]], dtype='float32') - + cdef np.ndarray[np.uint16_t, ndim=3, mode="c"] H_i = \ np.zeros([dims[0], dims[1],dims[2]], dtype='uint16') - + cdef np.ndarray[np.uint16_t, ndim=3, mode="c"] H_j = \ np.zeros([dims[0], dims[1],dims[2]], dtype='uint16') @@ -536,16 +569,16 @@ def PatchSel_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] dims[3] = neighbours - + cdef np.ndarray[np.float32_t, ndim=4, mode="c"] Weights = \ np.zeros([dims[3],dims[0],dims[1],dims[2]], dtype='float32') - + cdef np.ndarray[np.uint16_t, ndim=4, mode="c"] H_i = \ np.zeros([dims[3],dims[0],dims[1],dims[2]], dtype='uint16') - + cdef np.ndarray[np.uint16_t, ndim=4, mode="c"] H_j = \ np.zeros([dims[3],dims[0],dims[1],dims[2]], dtype='uint16') - + cdef np.ndarray[np.uint16_t, ndim=4, mode="c"] H_k = \ np.zeros([dims[3],dims[0],dims[1],dims[2]], dtype='uint16') @@ -573,10 +606,10 @@ def NLTV_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] neighbours = H_i.shape[0] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ np.zeros([dims[0],dims[1]], dtype='float32') - + # Run nonlocal TV regularisation Nonlocal_TV_CPU_main(&inputData[0,0], &outputData[0,0], &H_i[0,0,0], &H_j[0,0,0], &H_i[0,0,0], &Weights[0,0,0], dims[1], dims[0], 0, neighbours, regularisation_parameter, iterations) return outputData @@ -590,7 +623,7 @@ def NDF_INPAINT_CPU(inputData, maskData, regularisation_parameter, edge_paramete elif inputData.ndim == 3: return NDF_INP_3D(inputData, maskData, regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, penalty_type) -def NDF_INP_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def NDF_INP_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, np.ndarray[np.uint8_t, ndim=2, mode="c"] maskData, float regularisation_parameter, float edge_parameter, @@ -605,12 +638,12 @@ def NDF_INP_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ np.zeros([dims[0],dims[1]], dtype='float32') - - # Run Inpaiting by Diffusion iterations for 2D data + + # Run Inpaiting by Diffusion iterations for 2D data Diffusion_Inpaint_CPU_main(&inputData[0,0], &maskData[0,0], &outputData[0,0], regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, penalty_type, dims[1], dims[0], 1) return outputData - -def NDF_INP_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + +def NDF_INP_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, np.ndarray[np.uint8_t, ndim=3, mode="c"] maskData, float regularisation_parameter, float edge_parameter, @@ -621,11 +654,11 @@ def NDF_INP_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ np.zeros([dims[0],dims[1],dims[2]], dtype='float32') - - # Run Inpaiting by Diffusion iterations for 3D data + + # Run Inpaiting by Diffusion iterations for 3D data Diffusion_Inpaint_CPU_main(&inputData[0,0,0], &maskData[0,0,0], &outputData[0,0,0], regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, penalty_type, dims[2], dims[1], dims[0]) return outputData @@ -636,27 +669,27 @@ def NVM_INPAINT_CPU(inputData, maskData, SW_increment, iterationsNumb): if inputData.ndim == 2: return NVM_INP_2D(inputData, maskData, SW_increment, iterationsNumb) elif inputData.ndim == 3: - return + return -def NVM_INP_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def NVM_INP_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, np.ndarray[np.uint8_t, ndim=2, mode="c"] maskData, int SW_increment, int iterationsNumb): cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ - np.zeros([dims[0],dims[1]], dtype='float32') - + np.zeros([dims[0],dims[1]], dtype='float32') + cdef np.ndarray[np.uint8_t, ndim=2, mode="c"] maskData_upd = \ np.zeros([dims[0],dims[1]], dtype='uint8') - - # Run Inpaiting by Nonlocal vertical marching method for 2D data - NonlocalMarching_Inpaint_main(&inputData[0,0], &maskData[0,0], &outputData[0,0], + + # Run Inpaiting by Nonlocal vertical marching method for 2D data + NonlocalMarching_Inpaint_main(&inputData[0,0], &maskData[0,0], &outputData[0,0], &maskData_upd[0,0], SW_increment, iterationsNumb, 1, dims[1], dims[0], 1) - + return (outputData, maskData_upd) @@ -669,36 +702,36 @@ def TV_ENERGY(inputData, inputData0, regularisation_parameter, typeFunctional): elif inputData.ndim == 3: return TV_ENERGY_3D(inputData, inputData0, regularisation_parameter, typeFunctional) -def TV_ENERGY_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, - np.ndarray[np.float32_t, ndim=2, mode="c"] inputData0, +def TV_ENERGY_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, + np.ndarray[np.float32_t, ndim=2, mode="c"] inputData0, float regularisation_parameter, int typeFunctional): - + cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] outputData = \ np.zeros([1], dtype='float32') - - # run function + + # run function TV_energy2D(&inputData[0,0], &inputData0[0,0], &outputData[0], regularisation_parameter, typeFunctional, dims[1], dims[0]) - + return outputData - + def TV_ENERGY_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, - np.ndarray[np.float32_t, ndim=3, mode="c"] inputData0, + np.ndarray[np.float32_t, ndim=3, mode="c"] inputData0, float regularisation_parameter, int typeFunctional): - + cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] outputData = \ np.zeros([1], dtype='float32') - + # Run function TV_energy3D(&inputData[0,0,0], &inputData0[0,0,0], &outputData[0], regularisation_parameter, typeFunctional, dims[2], dims[1], dims[0]) diff --git a/src/Python/src/gpu_regularisers.pyx b/src/Python/src/gpu_regularisers.pyx index 6fc4135..84ee981 100644 --- a/src/Python/src/gpu_regularisers.pyx +++ b/src/Python/src/gpu_regularisers.pyx @@ -24,68 +24,68 @@ cdef extern int TV_ROF_GPU_main(float* Input, float* Output, float *infovector, cdef extern int TV_FGP_GPU_main(float *Input, float *Output, float *infovector, float lambdaPar, int iter, float epsil, int methodTV, int nonneg, int N, int M, int Z); cdef extern int TV_SB_GPU_main(float *Input, float *Output, float *infovector, float lambdaPar, int iter, float epsil, int methodTV, int N, int M, int Z); cdef extern int LLT_ROF_GPU_main(float *Input, float *Output, float *infovector, float lambdaROF, float lambdaLLT, int iterationsNumb, float tau, float epsil, int N, int M, int Z); -cdef extern int TGV_GPU_main(float *Input, float *Output, float lambdaPar, float alpha1, float alpha0, int iterationsNumb, float L2, int dimX, int dimY, int dimZ); -cdef extern int NonlDiff_GPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, int N, int M, int Z); -cdef extern int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, float lambdaPar, int iterationsNumb, float epsil, float eta, int methodTV, int nonneg, int printM, int N, int M, int Z); -cdef extern int Diffus4th_GPU_main(float *Input, float *Output, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int N, int M, int Z); +cdef extern int TGV_GPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float alpha1, float alpha0, int iterationsNumb, float L2, float epsil, int dimX, int dimY, int dimZ); +cdef extern int NonlDiff_GPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, int penaltytype, float epsil, int N, int M, int Z); +cdef extern int Diffus4th_GPU_main(float *Input, float *Output, float *infovector, float lambdaPar, float sigmaPar, int iterationsNumb, float tau, float epsil, int N, int M, int Z); +cdef extern int dTV_FGP_GPU_main(float *Input, float *InputRef, float *Output, float *infovector, float lambdaPar, int iterationsNumb, float epsil, float eta, int methodTV, int nonneg, int N, int M, int Z); cdef extern int PatchSelect_GPU_main(float *Input, unsigned short *H_i, unsigned short *H_j, float *Weights, int N, int M, int SearchWindow, int SimilarWin, int NumNeighb, float h); # Total-variation Rudin-Osher-Fatemi (ROF) def TV_ROF_GPU(inputData, regularisation_parameter, - iterations, + iterations, time_marching_parameter, tolerance_param): if inputData.ndim == 2: - return ROFTV2D(inputData, + return ROFTV2D(inputData, regularisation_parameter, iterations, time_marching_parameter, tolerance_param) elif inputData.ndim == 3: - return ROFTV3D(inputData, + return ROFTV3D(inputData, regularisation_parameter, - iterations, + iterations, time_marching_parameter, tolerance_param) - + # Total-variation Fast-Gradient-Projection (FGP) def TV_FGP_GPU(inputData, regularisation_parameter, - iterations, + iterations, tolerance_param, methodTV, nonneg): if inputData.ndim == 2: return FGPTV2D(inputData, regularisation_parameter, - iterations, + iterations, tolerance_param, methodTV, nonneg) elif inputData.ndim == 3: return FGPTV3D(inputData, regularisation_parameter, - iterations, + iterations, tolerance_param, methodTV, nonneg) # Total-variation Split Bregman (SB) def TV_SB_GPU(inputData, regularisation_parameter, - iterations, + iterations, tolerance_param, methodTV): if inputData.ndim == 2: return SBTV2D(inputData, regularisation_parameter, - iterations, + iterations, tolerance_param, methodTV) elif inputData.ndim == 3: return SBTV3D(inputData, regularisation_parameter, - iterations, + iterations, tolerance_param, methodTV) # LLT-ROF model @@ -95,90 +95,93 @@ def LLT_ROF_GPU(inputData, regularisation_parameterROF, regularisation_parameter elif inputData.ndim == 3: return LLT_ROF_GPU3D(inputData, regularisation_parameterROF, regularisation_parameterLLT, iterations, time_marching_parameter, tolerance_param) # Total Generilised Variation (TGV) -def TGV_GPU(inputData, regularisation_parameter, alpha1, alpha0, iterations, LipshitzConst): +def TGV_GPU(inputData, regularisation_parameter, alpha1, alpha0, iterations, LipshitzConst, tolerance_param): if inputData.ndim == 2: - return TGV2D(inputData, regularisation_parameter, alpha1, alpha0, iterations, LipshitzConst) + return TGV2D(inputData, regularisation_parameter, alpha1, alpha0, iterations, LipshitzConst, tolerance_param) elif inputData.ndim == 3: - return TGV3D(inputData, regularisation_parameter, alpha1, alpha0, iterations, LipshitzConst) + return TGV3D(inputData, regularisation_parameter, alpha1, alpha0, iterations, LipshitzConst, tolerance_param) # Directional Total-variation Fast-Gradient-Projection (FGP) def dTV_FGP_GPU(inputData, refdata, regularisation_parameter, - iterations, + iterations, tolerance_param, eta_const, methodTV, - nonneg, - printM): + nonneg): if inputData.ndim == 2: return FGPdTV2D(inputData, refdata, regularisation_parameter, - iterations, + iterations, tolerance_param, eta_const, methodTV, - nonneg, - printM) + nonneg) elif inputData.ndim == 3: return FGPdTV3D(inputData, refdata, regularisation_parameter, - iterations, + iterations, tolerance_param, eta_const, methodTV, - nonneg, - printM) + nonneg) # Nonlocal Isotropic Diffusion (NDF) def NDF_GPU(inputData, regularisation_parameter, edge_parameter, - iterations, + iterations, time_marching_parameter, - penalty_type): + penalty_type, + tolerance_param): if inputData.ndim == 2: return NDF_GPU_2D(inputData, regularisation_parameter, edge_parameter, - iterations, + iterations, time_marching_parameter, - penalty_type) + penalty_type, + tolerance_param) elif inputData.ndim == 3: return NDF_GPU_3D(inputData, regularisation_parameter, edge_parameter, - iterations, + iterations, time_marching_parameter, - penalty_type) + penalty_type, + tolerance_param) # Anisotropic Fourth-Order diffusion def Diff4th_GPU(inputData, regularisation_parameter, edge_parameter, - iterations, - time_marching_parameter): + iterations, + time_marching_parameter, + tolerance_param): if inputData.ndim == 2: return Diff4th_2D(inputData, regularisation_parameter, edge_parameter, - iterations, - time_marching_parameter) + iterations, + time_marching_parameter, + tolerance_param) elif inputData.ndim == 3: return Diff4th_3D(inputData, regularisation_parameter, edge_parameter, - iterations, - time_marching_parameter) - + iterations, + time_marching_parameter, + tolerance_param) + #****************************************************************# #********************** Total-variation ROF *********************# #****************************************************************# -def ROFTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def ROFTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameter, - int iterations, + int iterations, float time_marching_parameter, float tolerance_param): - + cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] @@ -187,25 +190,25 @@ def ROFTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, np.zeros([dims[0],dims[1]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.ones([2], dtype='float32') - + # Running CUDA code here if (TV_ROF_GPU_main( &inputData[0,0], &outputData[0,0], &infovec[0], regularisation_parameter, - iterations, - time_marching_parameter, + iterations, + time_marching_parameter, tolerance_param, dims[1], dims[0], 1)==0): return (outputData,infovec) else: raise ValueError(CUDAErrorMessage); - -def ROFTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + +def ROFTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, - int iterations, + int iterations, float time_marching_parameter, float tolerance_param): - + cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] @@ -215,13 +218,13 @@ def ROFTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, np.zeros([dims[0],dims[1],dims[2]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.ones([2], dtype='float32') - - # Running CUDA code here + + # Running CUDA code here if (TV_ROF_GPU_main( &inputData[0,0,0], &outputData[0,0,0], &infovec[0], regularisation_parameter, - iterations, - time_marching_parameter, + iterations, + time_marching_parameter, tolerance_param, dims[2], dims[1], dims[0])==0): return (outputData,infovec) @@ -231,13 +234,13 @@ def ROFTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, #********************** Total-variation FGP *********************# #****************************************************************# #******** Total-variation Fast-Gradient-Projection (FGP)*********# -def FGPTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def FGPTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameter, - int iterations, + int iterations, float tolerance_param, int methodTV, int nonneg): - + cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] @@ -246,10 +249,10 @@ def FGPTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, np.zeros([dims[0],dims[1]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.ones([2], dtype='float32') - - # Running CUDA code here + + # Running CUDA code here if (TV_FGP_GPU_main(&inputData[0,0], &outputData[0,0], &infovec[0], - regularisation_parameter, + regularisation_parameter, iterations, tolerance_param, methodTV, @@ -258,14 +261,14 @@ def FGPTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, return (outputData,infovec) else: raise ValueError(CUDAErrorMessage); - -def FGPTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + +def FGPTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, - int iterations, + int iterations, float tolerance_param, int methodTV, int nonneg): - + cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] @@ -276,11 +279,11 @@ def FGPTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, np.zeros([dims[0],dims[1],dims[2]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.ones([2], dtype='float32') - - # Running CUDA code here + + # Running CUDA code here if (TV_FGP_GPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], - regularisation_parameter, - iterations, + regularisation_parameter, + iterations, tolerance_param, methodTV, nonneg, @@ -293,12 +296,12 @@ def FGPTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, #********************** Total-variation SB *********************# #***************************************************************# #*************** Total-variation Split Bregman (SB)*************# -def SBTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def SBTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameter, - int iterations, + int iterations, float tolerance_param, int methodTV): - + cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] @@ -307,11 +310,11 @@ def SBTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, np.zeros([dims[0],dims[1]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.ones([2], dtype='float32') - + # Running CUDA code here if (TV_SB_GPU_main(&inputData[0,0], &outputData[0,0],&infovec[0], - regularisation_parameter, - iterations, + regularisation_parameter, + iterations, tolerance_param, methodTV, dims[1], dims[0], 1)==0): @@ -319,13 +322,13 @@ def SBTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, else: raise ValueError(CUDAErrorMessage); - -def SBTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + +def SBTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, - int iterations, + int iterations, float tolerance_param, int methodTV): - + cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] @@ -335,11 +338,11 @@ def SBTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, np.zeros([dims[0],dims[1],dims[2]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.ones([2], dtype='float32') - - # Running CUDA code here + + # Running CUDA code here if (TV_SB_GPU_main(&inputData[0,0,0], &outputData[0,0,0],&infovec[0], - regularisation_parameter , - iterations, + regularisation_parameter , + iterations, tolerance_param, methodTV, dims[2], dims[1], dims[0])==0): @@ -352,13 +355,13 @@ def SBTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, #************************ LLT-ROF model ************************# #***************************************************************# #************Joint LLT-ROF model for higher order **************# -def LLT_ROF_GPU2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def LLT_ROF_GPU2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameterROF, float regularisation_parameterLLT, - int iterations, + int iterations, float time_marching_parameter, float tolerance_param): - + cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] @@ -367,24 +370,24 @@ def LLT_ROF_GPU2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, np.zeros([dims[0],dims[1]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.ones([2], dtype='float32') - - # Running CUDA code here - if (LLT_ROF_GPU_main(&inputData[0,0], &outputData[0,0],&infovec[0],regularisation_parameterROF, regularisation_parameterLLT, iterations, - time_marching_parameter, + + # Running CUDA code here + if (LLT_ROF_GPU_main(&inputData[0,0], &outputData[0,0],&infovec[0],regularisation_parameterROF, regularisation_parameterLLT, iterations, + time_marching_parameter, tolerance_param, dims[1],dims[0],1)==0): return (outputData,infovec) else: raise ValueError(CUDAErrorMessage); - -def LLT_ROF_GPU3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + +def LLT_ROF_GPU3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameterROF, float regularisation_parameterLLT, - int iterations, + int iterations, float time_marching_parameter, float tolerance_param): - + cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] @@ -394,11 +397,11 @@ def LLT_ROF_GPU3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, np.zeros([dims[0],dims[1],dims[2]], dtype='float32') cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ np.ones([2], dtype='float32') - + # Running CUDA code here - if (LLT_ROF_GPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], regularisation_parameterROF, regularisation_parameterLLT, - iterations, - time_marching_parameter, + if (LLT_ROF_GPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], regularisation_parameterROF, regularisation_parameterLLT, + iterations, + time_marching_parameter, tolerance_param, dims[2], dims[1], dims[0])==0): return (outputData,infovec) @@ -409,38 +412,43 @@ def LLT_ROF_GPU3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, #***************************************************************# #***************** Total Generalised Variation *****************# #***************************************************************# -def TGV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def TGV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameter, float alpha1, float alpha0, - int iterationsNumb, - float LipshitzConst): - + int iterationsNumb, + float LipshitzConst, + float tolerance_param): + cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ np.zeros([dims[0],dims[1]], dtype='float32') - + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.ones([2], dtype='float32') + #/* Run TGV iterations for 2D data */ - if (TGV_GPU_main(&inputData[0,0], &outputData[0,0], regularisation_parameter, + if (TGV_GPU_main(&inputData[0,0], &outputData[0,0], &infovec[0], regularisation_parameter, alpha1, alpha0, - iterationsNumb, + iterationsNumb, LipshitzConst, + tolerance_param, dims[1],dims[0], 1)==0): - return outputData + return (outputData,infovec) else: raise ValueError(CUDAErrorMessage); -def TGV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, +def TGV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, float alpha1, float alpha0, - int iterationsNumb, - float LipshitzConst): - + int iterationsNumb, + float LipshitzConst, + float tolerance_param): + cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] @@ -448,178 +456,205 @@ def TGV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ np.zeros([dims[0],dims[1],dims[2]], dtype='float32') - - # Running CUDA code here + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.ones([2], dtype='float32') + + # Running CUDA code here if (TGV_GPU_main( - &inputData[0,0,0], &outputData[0,0,0], regularisation_parameter, + &inputData[0,0,0], &outputData[0,0,0], &infovec[0], regularisation_parameter, alpha1, alpha0, - iterationsNumb, + iterationsNumb, LipshitzConst, + tolerance_param, dims[2], dims[1], dims[0])==0): - return outputData; + return (outputData,infovec) else: raise ValueError(CUDAErrorMessage); - #****************************************************************# -#**************Directional Total-variation FGP ******************# +#***************Nonlinear (Isotropic) Diffusion******************# #****************************************************************# -#******** Directional TV Fast-Gradient-Projection (FGP)*********# -def FGPdTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, - np.ndarray[np.float32_t, ndim=2, mode="c"] refdata, +def NDF_GPU_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameter, - int iterations, - float tolerance_param, - float eta_const, - int methodTV, - int nonneg, - int printM): - + float edge_parameter, + int iterationsNumb, + float time_marching_parameter, + int penalty_type, + float tolerance_param): cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ - np.zeros([dims[0],dims[1]], dtype='float32') - - # Running CUDA code here - if (dTV_FGP_GPU_main(&inputData[0,0], &refdata[0,0], &outputData[0,0], - regularisation_parameter, - iterations, - tolerance_param, - eta_const, - methodTV, - nonneg, - printM, - dims[1], dims[0], 1)==0): - return outputData + np.zeros([dims[0],dims[1]], dtype='float32') + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.ones([2], dtype='float32') + + #rangecheck = penalty_type < 1 and penalty_type > 3 + #if not rangecheck: +# raise ValueError('Choose penalty type as 1 for Huber, 2 - Perona-Malik, 3 - Tukey Biweight') + + # Run Nonlinear Diffusion iterations for 2D data + # Running CUDA code here + if (NonlDiff_GPU_main(&inputData[0,0], &outputData[0,0],&infovec[0], + regularisation_parameter, + edge_parameter, iterationsNumb, + time_marching_parameter, penalty_type, + tolerance_param, + dims[1], dims[0], 1)==0): + return (outputData,infovec) else: raise ValueError(CUDAErrorMessage); - - -def FGPdTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, - np.ndarray[np.float32_t, ndim=3, mode="c"] refdata, +def NDF_GPU_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, - int iterations, - float tolerance_param, - float eta_const, - int methodTV, - int nonneg, - int printM): - + float edge_parameter, + int iterationsNumb, + float time_marching_parameter, + int penalty_type, + float tolerance_param): cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ - np.zeros([dims[0],dims[1],dims[2]], dtype='float32') - - # Running CUDA code here - if (dTV_FGP_GPU_main(&inputData[0,0,0], &refdata[0,0,0], &outputData[0,0,0], - regularisation_parameter , - iterations, - tolerance_param, - eta_const, - methodTV, - nonneg, - printM, - dims[2], dims[1], dims[0])==0): - return outputData; + np.zeros([dims[0],dims[1],dims[2]], dtype='float32') + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.ones([2], dtype='float32') + + # Run Nonlinear Diffusion iterations for 3D data + # Running CUDA code here + if (NonlDiff_GPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], + regularisation_parameter, edge_parameter, + iterationsNumb, time_marching_parameter, + penalty_type, + tolerance_param, + dims[2], dims[1], dims[0])==0): + return (outputData,infovec) else: raise ValueError(CUDAErrorMessage); - #****************************************************************# -#***************Nonlinear (Isotropic) Diffusion******************# +#************Anisotropic Fourth-Order diffusion******************# #****************************************************************# -def NDF_GPU_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +def Diff4th_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, float regularisation_parameter, float edge_parameter, - int iterationsNumb, + int iterationsNumb, float time_marching_parameter, - int penalty_type): + float tolerance_param): cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ np.zeros([dims[0],dims[1]], dtype='float32') - - #rangecheck = penalty_type < 1 and penalty_type > 3 - #if not rangecheck: -# raise ValueError('Choose penalty type as 1 for Huber, 2 - Perona-Malik, 3 - Tukey Biweight') - - # Run Nonlinear Diffusion iterations for 2D data - # Running CUDA code here - if (NonlDiff_GPU_main(&inputData[0,0], &outputData[0,0], regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, penalty_type, dims[1], dims[0], 1)==0): - return outputData; + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.ones([2], dtype='float32') + + # Run Anisotropic Fourth-Order diffusion for 2D data + # Running CUDA code here + if (Diffus4th_GPU_main(&inputData[0,0], &outputData[0,0], &infovec[0], + regularisation_parameter, edge_parameter, iterationsNumb, + time_marching_parameter, + tolerance_param, + dims[1], dims[0], 1)==0): + return (outputData,infovec) else: raise ValueError(CUDAErrorMessage); - -def NDF_GPU_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, +def Diff4th_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, float regularisation_parameter, float edge_parameter, - int iterationsNumb, + int iterationsNumb, float time_marching_parameter, - int penalty_type): + float tolerance_param): cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ - np.zeros([dims[0],dims[1],dims[2]], dtype='float32') - - # Run Nonlinear Diffusion iterations for 3D data - # Running CUDA code here - if (NonlDiff_GPU_main(&inputData[0,0,0], &outputData[0,0,0], regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, penalty_type, dims[2], dims[1], dims[0])==0): - return outputData; + np.zeros([dims[0],dims[1],dims[2]], dtype='float32') + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.ones([2], dtype='float32') + + # Run Anisotropic Fourth-Order diffusion for 3D data + # Running CUDA code here + if (Diffus4th_GPU_main(&inputData[0,0,0], &outputData[0,0,0], &infovec[0], + regularisation_parameter, edge_parameter, + iterationsNumb, time_marching_parameter, + tolerance_param, + dims[2], dims[1], dims[0])==0): + return (outputData,infovec) else: raise ValueError(CUDAErrorMessage); - #****************************************************************# -#************Anisotropic Fourth-Order diffusion******************# +#**************Directional Total-variation FGP ******************# #****************************************************************# -def Diff4th_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, +#******** Directional TV Fast-Gradient-Projection (FGP)*********# +def FGPdTV2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, + np.ndarray[np.float32_t, ndim=2, mode="c"] refdata, float regularisation_parameter, - float edge_parameter, - int iterationsNumb, - float time_marching_parameter): + int iterations, + float tolerance_param, + float eta_const, + int methodTV, + int nonneg): + cdef long dims[2] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] - + cdef np.ndarray[np.float32_t, ndim=2, mode="c"] outputData = \ - np.zeros([dims[0],dims[1]], dtype='float32') - - # Run Anisotropic Fourth-Order diffusion for 2D data - # Running CUDA code here - if (Diffus4th_GPU_main(&inputData[0,0], &outputData[0,0], regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, dims[1], dims[0], 1)==0): - return outputData + np.zeros([dims[0],dims[1]], dtype='float32') + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.ones([2], dtype='float32') + + # Running CUDA code here + if (dTV_FGP_GPU_main(&inputData[0,0], &refdata[0,0], &outputData[0,0], &infovec[0], + regularisation_parameter, + iterations, + tolerance_param, + eta_const, + methodTV, + nonneg, + dims[1], dims[0], 1)==0): + return (outputData,infovec) else: raise ValueError(CUDAErrorMessage); - -def Diff4th_3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + +def FGPdTV3D(np.ndarray[np.float32_t, ndim=3, mode="c"] inputData, + np.ndarray[np.float32_t, ndim=3, mode="c"] refdata, float regularisation_parameter, - float edge_parameter, - int iterationsNumb, - float time_marching_parameter): + int iterations, + float tolerance_param, + float eta_const, + int methodTV, + int nonneg): + cdef long dims[3] dims[0] = inputData.shape[0] dims[1] = inputData.shape[1] dims[2] = inputData.shape[2] - + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] outputData = \ - np.zeros([dims[0],dims[1],dims[2]], dtype='float32') - - # Run Anisotropic Fourth-Order diffusion for 3D data - # Running CUDA code here - if (Diffus4th_GPU_main(&inputData[0,0,0], &outputData[0,0,0], regularisation_parameter, edge_parameter, iterationsNumb, time_marching_parameter, dims[2], dims[1], dims[0])==0): - return outputData; + np.zeros([dims[0],dims[1],dims[2]], dtype='float32') + cdef np.ndarray[np.float32_t, ndim=1, mode="c"] infovec = \ + np.ones([2], dtype='float32') + + # Running CUDA code here + if (dTV_FGP_GPU_main(&inputData[0,0,0], &refdata[0,0,0], &outputData[0,0,0], &infovec[0], + regularisation_parameter , + iterations, + tolerance_param, + eta_const, + methodTV, + nonneg, + dims[2], dims[1], dims[0])==0): + return (outputData,infovec) else: raise ValueError(CUDAErrorMessage); @@ -639,14 +674,14 @@ def PatchSel_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, cdef long dims[3] dims[0] = neighbours dims[1] = inputData.shape[0] - dims[2] = inputData.shape[1] - + dims[2] = inputData.shape[1] + cdef np.ndarray[np.float32_t, ndim=3, mode="c"] Weights = \ np.zeros([dims[0], dims[1],dims[2]], dtype='float32') - + cdef np.ndarray[np.uint16_t, ndim=3, mode="c"] H_i = \ np.zeros([dims[0], dims[1],dims[2]], dtype='uint16') - + cdef np.ndarray[np.uint16_t, ndim=3, mode="c"] H_j = \ np.zeros([dims[0], dims[1],dims[2]], dtype='uint16') @@ -655,4 +690,3 @@ def PatchSel_2D(np.ndarray[np.float32_t, ndim=2, mode="c"] inputData, return H_i, H_j, Weights; else: raise ValueError(CUDAErrorMessage); - |