summaryrefslogtreecommitdiffstats
path: root/main_func
diff options
context:
space:
mode:
Diffstat (limited to 'main_func')
-rw-r--r--main_func/FISTA_REC.m100
-rw-r--r--main_func/compile_mex.m8
-rw-r--r--main_func/regularizers_CPU/FGP_TV.c (renamed from main_func/FGP_TV.c)0
-rw-r--r--main_func/regularizers_CPU/LLT_model.c (renamed from main_func/LLT_model.c)0
-rw-r--r--main_func/regularizers_CPU/PatchBased_Regul.c295
-rw-r--r--main_func/regularizers_CPU/SplitBregman_TV.c (renamed from main_func/SplitBregman_TV.c)0
-rw-r--r--main_func/regularizers_CPU/TGV_PD.c353
7 files changed, 713 insertions, 43 deletions
diff --git a/main_func/FISTA_REC.m b/main_func/FISTA_REC.m
index db2b581..2823691 100644
--- a/main_func/FISTA_REC.m
+++ b/main_func/FISTA_REC.m
@@ -15,7 +15,6 @@ function [X, output] = FISTA_REC(params)
%----------------Regularization choices------------------------
% - .Regul_Lambda_FGPTV (FGP-TV regularization parameter)
% - .Regul_Lambda_SBTV (SplitBregman-TV regularization parameter)
-% - .Regul_Lambda_L1 (L1 regularization by soft-thresholding)
% - .Regul_Lambda_TVLLT (Higher order SB-LLT regularization parameter)
% - .Regul_tol (tolerance to terminate regul iterations, default 1.0e-04)
% - .Regul_Iterations (iterations for the selected penalty, default 25)
@@ -28,7 +27,7 @@ function [X, output] = FISTA_REC(params)
% - .slice (for 3D volumes - slice number to imshow)
% ___Output___:
% 1. X - reconstructed image/volume
-% 2. output - structure with
+% 2. output - a structure with
% - .Resid_error - residual error (if X_ideal is given)
% - .objective: value of the objective function
% - .L_const: Lipshitz constant to avoid recalculations
@@ -74,21 +73,50 @@ if (isfield(params,'L_const'))
L_const = params.L_const;
else
% using Power method (PM) to establish L constant
- niter = 8; % number of iteration for PM
- x = rand(N,N,SlicesZ);
- sqweight = sqrt(weights);
- [sino_id, y] = astra_create_sino3d_cuda(x, proj_geom, vol_geom);
- y = sqweight.*y;
- astra_mex_data3d('delete', sino_id);
-
- for i = 1:niter
- [id,x] = astra_create_backprojection3d_cuda(sqweight.*y, proj_geom, vol_geom);
- s = norm(x(:));
- x = x/s;
- [sino_id, y] = astra_create_sino3d_cuda(x, proj_geom, vol_geom);
+ if (strcmp(proj_geom.type,'parallel') || strcmp(proj_geom.type,'parallel3d'))
+ % for parallel geometry we can do just one slice
+ fprintf('%s \n', 'Calculating Lipshitz constant for parallel beam geometry...');
+ niter = 15; % number of iteration for the PM
+ x1 = rand(N,N,1);
+ sqweight = sqrt(weights(:,:,1));
+ proj_geomT = proj_geom;
+ proj_geomT.DetectorRowCount = 1;
+ vol_geomT = vol_geom;
+ vol_geomT.GridSliceCount = 1;
+ [sino_id, y] = astra_create_sino3d_cuda(x1, proj_geomT, vol_geomT);
y = sqweight.*y;
astra_mex_data3d('delete', sino_id);
- astra_mex_data3d('delete', id);
+
+ for i = 1:niter
+ [id,x1] = astra_create_backprojection3d_cuda(sqweight.*y, proj_geomT, vol_geomT);
+ s = norm(x1(:));
+ x1 = x1/s;
+ [sino_id, y] = astra_create_sino3d_cuda(x1, proj_geomT, vol_geomT);
+ y = sqweight.*y;
+ astra_mex_data3d('delete', sino_id);
+ astra_mex_data3d('delete', id);
+ end
+ clear proj_geomT vol_geomT
+ else
+ % divergen beam geometry
+ fprintf('%s \n', 'Calculating Lipshitz constant for divergen beam geometry...');
+ niter = 8; % number of iteration for PM
+ x1 = rand(N,N,SlicesZ);
+ sqweight = sqrt(weights);
+ [sino_id, y] = astra_create_sino3d_cuda(x1, proj_geom, vol_geom);
+ y = sqweight.*y;
+ astra_mex_data3d('delete', sino_id);
+
+ for i = 1:niter
+ [id,x1] = astra_create_backprojection3d_cuda(sqweight.*y, proj_geom, vol_geom);
+ s = norm(x1(:));
+ x1 = x1/s;
+ [sino_id, y] = astra_create_sino3d_cuda(x1, proj_geom, vol_geom);
+ y = sqweight.*y;
+ astra_mex_data3d('delete', sino_id);
+ astra_mex_data3d('delete', id);
+ end
+ clear x1
end
L_const = s;
end
@@ -112,11 +140,6 @@ if (isfield(params,'Regul_Lambda_SBTV'))
else
lambdaSB_TV = 0;
end
-if (isfield(params,'Regul_Lambda_L1'))
- lambdaL1 = params.Regul_Lambda_L1;
-else
- lambdaL1 = 0;
-end
if (isfield(params,'Regul_tol'))
tol = params.Regul_tol;
else
@@ -194,19 +217,18 @@ else
X = zeros(N,N,SlicesZ, 'single'); % storage for the solution
end
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-Resid_error = zeros(iterFISTA,1); % error vector
-objective = zeros(iterFISTA,1); % obhective vector
+%----------------Reconstruction part------------------------
+Resid_error = zeros(iterFISTA,1); % errors vector (if the ground truth is given)
+objective = zeros(iterFISTA,1); % objective function values vector
t = 1;
X_t = X;
-% add_ring = zeros(size(sino),'single'); % size of sinogram array
r = zeros(Detectors,SlicesZ, 'single'); % 2D array (for 3D data) of sparse "ring" vectors
r_x = r; % another ring variable
residual = zeros(size(sino),'single');
-% Outer iterations loop
+% Outer FISTA iterations loop
for i = 1:iterFISTA
X_old = X;
@@ -216,12 +238,10 @@ for i = 1:iterFISTA
[sino_id, sino_updt] = astra_create_sino3d_cuda(X_t, proj_geom, vol_geom);
if (lambdaR_L1 > 0)
- % add ring removal part (Group-Huber fidelity)
+ % ring removal part (Group-Huber fidelity)
for kkk = 1:anglesNumb
- % add_ring(:,kkk,:) = squeeze(sino(:,kkk,:)) - alpha_ring.*r_x;
residual(:,kkk,:) = squeeze(weights(:,kkk,:)).*(squeeze(sino_updt(:,kkk,:)) - (squeeze(sino(:,kkk,:)) - alpha_ring.*r_x));
- end
-
+ end
vec = sum(residual,2);
if (SlicesZ > 1)
vec = squeeze(vec(:,1,:));
@@ -229,9 +249,10 @@ for i = 1:iterFISTA
r = r_x - (1./L_const).*vec;
else
% no ring removal
- residual = weights.*(sino_updt - sino);
+ residual = weights.*(sino_updt - sino);
end
- % residual = weights.*(sino_updt - add_ring);
+
+ objective(i) = (0.5*norm(residual(:))^2)/(Detectors*anglesNumb*SlicesZ); % for the objective function output
[id, x_temp] = astra_create_backprojection3d_cuda(residual, proj_geom, vol_geom);
@@ -242,27 +263,22 @@ for i = 1:iterFISTA
if (lambdaFGP_TV > 0)
% FGP-TV regularization
[X, f_val] = FGP_TV(single(X), lambdaFGP_TV, IterationsRegul, tol, 'iso');
- objective(i) = 0.5.*norm(residual(:))^2 + f_val;
+ objective(i) = objective(i) + f_val;
end
if (lambdaSB_TV > 0)
% Split Bregman regularization
X = SplitBregman_TV(single(X), lambdaSB_TV, IterationsRegul, tol); % (more memory efficent)
- objective(i) = 0.5.*norm(residual(:))^2;
- end
- if (lambdaL1 > 0)
- % L1 soft-threhsolding regularization
- X = max(abs(X)-lambdaL1, 0).*sign(X);
- objective(i) = 0.5.*norm(residual(:))^2;
end
if (lambdaHO > 0)
% Higher Order (LLT) regularization
X2 = LLT_model(single(X), lambdaHO, tauHO, iterHO, 3.0e-05, 0);
X = 0.5.*(X + X2); % averaged combination of two solutions
- objective(i) = 0.5.*norm(residual(:))^2;
end
+
+
if (lambdaR_L1 > 0)
- r = max(abs(r)-lambdaR_L1, 0).*sign(r); % soft-thresholding operator
+ r = max(abs(r)-lambdaR_L1, 0).*sign(r); % soft-thresholding operator for ring vector
end
t = (1 + sqrt(1 + 4*t^2))/2; % updating t
@@ -281,9 +297,9 @@ for i = 1:iterFISTA
end
if (strcmp(X_ideal, 'none' ) == 0)
Resid_error(i) = RMSE(X(ROI), X_ideal(ROI));
- fprintf('%s %i %s %s %.4f %s %s %.4f \n', 'Iteration Number:', i, '|', 'Error RMSE:', Resid_error(i), '|', 'Objective:', objective(i));
+ fprintf('%s %i %s %s %.4f %s %s %f \n', 'Iteration Number:', i, '|', 'Error RMSE:', Resid_error(i), '|', 'Objective:', objective(i));
else
- fprintf('%s %i %s %s %.4f \n', 'Iteration Number:', i, '|', 'Objective:', objective(i));
+ fprintf('%s %i %s %s %f \n', 'Iteration Number:', i, '|', 'Objective:', objective(i));
end
end
output.Resid_error = Resid_error;
diff --git a/main_func/compile_mex.m b/main_func/compile_mex.m
index 4d97bc2..7bfa8eb 100644
--- a/main_func/compile_mex.m
+++ b/main_func/compile_mex.m
@@ -1,4 +1,10 @@
-% compile mex's
+% compile mex's once
+cd regularizers_CPU/
+
mex LLT_model.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp"
mex FGP_TV.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp"
mex SplitBregman_TV.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp"
+mex TGV_PD.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp"
+
+cd ../../
+cd demos
diff --git a/main_func/FGP_TV.c b/main_func/regularizers_CPU/FGP_TV.c
index 1a1fd13..1a1fd13 100644
--- a/main_func/FGP_TV.c
+++ b/main_func/regularizers_CPU/FGP_TV.c
diff --git a/main_func/LLT_model.c b/main_func/regularizers_CPU/LLT_model.c
index 0aed31e..0aed31e 100644
--- a/main_func/LLT_model.c
+++ b/main_func/regularizers_CPU/LLT_model.c
diff --git a/main_func/regularizers_CPU/PatchBased_Regul.c b/main_func/regularizers_CPU/PatchBased_Regul.c
new file mode 100644
index 0000000..1ed29d4
--- /dev/null
+++ b/main_func/regularizers_CPU/PatchBased_Regul.c
@@ -0,0 +1,295 @@
+#define _USE_MATH_DEFINES
+
+#include "mex.h"
+#include <matrix.h>
+#include <math.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <stdio.h>
+#include "omp.h"
+
+/* C-OMP implementation of patch-based (PB) regularization (2D and 3D cases).
+ * This method finds self-similar patches in data and performs one fixed point iteration to mimimize the PB penalty function
+ *
+ * References: 1. Yang Z. & Jacob M. "Nonlocal Regularization of Inverse Problems"
+ * 2. Kazantsev D. et al. "4D-CT reconstruction with unified spatial-temporal patch-based regularization"
+ *
+ * Input Parameters (mandatory):
+ * 1. Image (2D or 3D)
+ * 2. ratio of the searching window (e.g. 3 = (2*3+1) = 7 pixels window)
+ * 3. ratio of the similarity window (e.g. 1 = (2*1+1) = 3 pixels window)
+ * 4. h - parameter for the PB penalty function
+ * 5. lambda - regularization parameter
+
+ * Output:
+ * 1. regularized (denoised) Image (N x N)/volume (N x N x N)
+ *
+ * Quick 2D denoising example in Matlab:
+ Im = double(imread('lena_gray_256.tif'))/255; % loading image
+ u0 = Im + .03*randn(size(Im)); u0(u0<0) = 0; % adding noise
+ ImDen = PB_Regul_CPU(single(u0), 3, 1, 0.08, 0.05);
+ *
+ * Please see more tests in a file:
+ TestTemporalSmoothing.m
+
+ *
+ * Matlab + C/mex compilers needed
+ * to compile with OMP support: mex PB_Regul_CPU.c CFLAGS="\$CFLAGS -fopenmp -Wall" LDFLAGS="\$LDFLAGS -fopenmp"
+ *
+ * D. Kazantsev *
+ * 02/07/2014
+ * Harwell, UK
+ */
+
+float pad_crop(float *A, float *Ap, int OldSizeX, int OldSizeY, int OldSizeZ, int NewSizeX, int NewSizeY, int NewSizeZ, int padXY, int switchpad_crop);
+float PB_FUNC2D(float *A, float *B, int dimX, int dimY, int padXY, int SearchW, int SimilW, float h, float lambda);
+float PB_FUNC3D(float *A, float *B, int dimX, int dimY, int dimZ, int padXY, int SearchW, int SimilW, float h, float lambda);
+
+void mexFunction(
+ int nlhs, mxArray *plhs[],
+ int nrhs, const mxArray *prhs[])
+{
+ int N, M, Z, numdims, SearchW, SimilW, SearchW_real, padXY, newsizeX, newsizeY, newsizeZ, switchpad_crop;
+ const int *dims;
+ float *A, *B=NULL, *Ap=NULL, *Bp=NULL, h, lambda;
+
+ numdims = mxGetNumberOfDimensions(prhs[0]);
+ dims = mxGetDimensions(prhs[0]);
+
+ N = dims[0];
+ M = dims[1];
+ Z = dims[2];
+
+ if ((numdims < 2) || (numdims > 3)) {mexErrMsgTxt("The input should be 2D image or 3D volume");}
+ if (mxGetClassID(prhs[0]) != mxSINGLE_CLASS) {mexErrMsgTxt("The input in single precision is required"); }
+
+ if(nrhs != 5) mexErrMsgTxt("Five inputs reqired: Image(2D,3D), SearchW, SimilW, Threshold, Regularization parameter");
+
+ /*Handling inputs*/
+ A = (float *) mxGetData(prhs[0]); /* the image to regularize/filter */
+ SearchW_real = (int) mxGetScalar(prhs[1]); /* the searching window ratio */
+ SimilW = (int) mxGetScalar(prhs[2]); /* the similarity window ratio */
+ h = (float) mxGetScalar(prhs[3]); /* parameter for the PB filtering function */
+ lambda = (float) mxGetScalar(prhs[4]); /* regularization parameter */
+
+ if (h <= 0) mexErrMsgTxt("Parmeter for the PB penalty function should be > 0");
+ if (lambda <= 0) mexErrMsgTxt(" Regularization parmeter should be > 0");
+
+ SearchW = SearchW_real + 2*SimilW;
+
+ /* SearchW_full = 2*SearchW + 1; */ /* the full searching window size */
+ /* SimilW_full = 2*SimilW + 1; */ /* the full similarity window size */
+
+
+ padXY = SearchW + 2*SimilW; /* padding sizes */
+ newsizeX = N + 2*(padXY); /* the X size of the padded array */
+ newsizeY = M + 2*(padXY); /* the Y size of the padded array */
+ newsizeZ = Z + 2*(padXY); /* the Z size of the padded array */
+ int N_dims[] = {newsizeX, newsizeY, newsizeZ};
+
+ /******************************2D case ****************************/
+ if (numdims == 2) {
+ /*Handling output*/
+ B = (float*)mxGetData(plhs[0] = mxCreateNumericMatrix(N, M, mxSINGLE_CLASS, mxREAL));
+ /*allocating memory for the padded arrays */
+ Ap = (float*)mxGetData(mxCreateNumericMatrix(newsizeX, newsizeY, mxSINGLE_CLASS, mxREAL));
+ Bp = (float*)mxGetData(mxCreateNumericMatrix(newsizeX, newsizeY, mxSINGLE_CLASS, mxREAL));
+ /**************************************************************************/
+ /*Perform padding of image A to the size of [newsizeX * newsizeY] */
+ switchpad_crop = 0; /*padding*/
+ pad_crop(A, Ap, M, N, 0, newsizeY, newsizeX, 0, padXY, switchpad_crop);
+
+ /* Do PB regularization with the padded array */
+ PB_FUNC2D(Ap, Bp, newsizeY, newsizeX, padXY, SearchW, SimilW, (float)h, (float)lambda);
+
+ switchpad_crop = 1; /*cropping*/
+ pad_crop(Bp, B, M, N, 0, newsizeY, newsizeX, 0, padXY, switchpad_crop);
+ }
+ else
+ {
+ /******************************3D case ****************************/
+ /*Handling output*/
+ B = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(3, dims, mxSINGLE_CLASS, mxREAL));
+ /*allocating memory for the padded arrays */
+ Ap = (float*)mxGetPr(mxCreateNumericArray(3, N_dims, mxSINGLE_CLASS, mxREAL));
+ Bp = (float*)mxGetPr(mxCreateNumericArray(3, N_dims, mxSINGLE_CLASS, mxREAL));
+ /**************************************************************************/
+
+ /*Perform padding of image A to the size of [newsizeX * newsizeY * newsizeZ] */
+ switchpad_crop = 0; /*padding*/
+ pad_crop(A, Ap, M, N, Z, newsizeY, newsizeX, newsizeZ, padXY, switchpad_crop);
+
+ /* Do PB regularization with the padded array */
+ PB_FUNC3D(Ap, Bp, newsizeY, newsizeX, newsizeZ, padXY, SearchW, SimilW, (float)h, (float)lambda);
+
+ switchpad_crop = 1; /*cropping*/
+ pad_crop(Bp, B, M, N, Z, newsizeY, newsizeX, newsizeZ, padXY, switchpad_crop);
+ } /*end else ndims*/
+}
+
+/*2D version*/
+float PB_FUNC2D(float *A, float *B, int dimX, int dimY, int padXY, int SearchW, int SimilW, float h, float lambda)
+{
+ int i, j, i_n, j_n, i_m, j_m, i_p, j_p, i_l, j_l, i1, j1, i2, j2, i3, j3, i5,j5, count, SimilW_full;
+ float *Eucl_Vec, h2, denh2, normsum, Weight, Weight_norm, value, denom, WeightGlob, t1;
+
+ /*SearchW_full = 2*SearchW + 1; */ /* the full searching window size */
+ SimilW_full = 2*SimilW + 1; /* the full similarity window size */
+ h2 = h*h;
+ denh2 = 1/(2*h2);
+
+ /*Gaussian kernel */
+ Eucl_Vec = (float*) calloc (SimilW_full*SimilW_full,sizeof(float));
+ count = 0;
+ for(i_n=-SimilW; i_n<=SimilW; i_n++) {
+ for(j_n=-SimilW; j_n<=SimilW; j_n++) {
+ t1 = pow(((float)i_n), 2) + pow(((float)j_n), 2);
+ Eucl_Vec[count] = exp(-(t1)/(2*SimilW*SimilW));
+ count = count + 1;
+ }} /*main neighb loop */
+
+ /*The NLM code starts here*/
+ /* setting OMP here */
+ #pragma omp parallel for shared (A, B, dimX, dimY, Eucl_Vec, lambda, denh2) private(denom, i, j, WeightGlob, count, i1, j1, i2, j2, i3, j3, i5, j5, Weight_norm, normsum, i_m, j_m, i_n, j_n, i_l, j_l, i_p, j_p, Weight, value)
+
+ for(i=0; i<dimX; i++) {
+ for(j=0; j<dimY; j++) {
+ if (((i >= padXY) && (i < dimX-padXY)) && ((j >= padXY) && (j < dimY-padXY))) {
+
+ /* Massive Search window loop */
+ Weight_norm = 0; value = 0.0;
+ for(i_m=-SearchW; i_m<=SearchW; i_m++) {
+ for(j_m=-SearchW; j_m<=SearchW; j_m++) {
+ /*checking boundaries*/
+ i1 = i+i_m; j1 = j+j_m;
+
+ WeightGlob = 0.0;
+ /* if inside the searching window */
+ for(i_l=-SimilW; i_l<=SimilW; i_l++) {
+ for(j_l=-SimilW; j_l<=SimilW; j_l++) {
+ i2 = i1+i_l; j2 = j1+j_l;
+
+ i3 = i+i_l; j3 = j+j_l; /*coordinates of the inner patch loop */
+
+ count = 0; normsum = 0.0;
+ for(i_p=-SimilW; i_p<=SimilW; i_p++) {
+ for(j_p=-SimilW; j_p<=SimilW; j_p++) {
+ i5 = i2 + i_p; j5 = j2 + j_p;
+ normsum = normsum + Eucl_Vec[count]*pow(A[(i3+i_p)*dimY+(j3+j_p)]-A[i5*dimY+j5], 2);
+ count = count + 1;
+ }}
+ if (normsum != 0) Weight = (exp(-normsum*denh2));
+ else Weight = 0.0;
+ WeightGlob += Weight;
+ }}
+
+ value += A[i1*dimY+j1]*WeightGlob;
+ Weight_norm += WeightGlob;
+ }} /*search window loop end*/
+
+ /* the final loop to average all values in searching window with weights */
+ denom = 1 + lambda*Weight_norm;
+ B[i*dimY+j] = (A[i*dimY+j] + lambda*value)/denom;
+ }
+ }} /*main loop*/
+ return (*B);
+ free(Eucl_Vec);
+}
+
+/*3D version*/
+ float PB_FUNC3D(float *A, float *B, int dimX, int dimY, int dimZ, int padXY, int SearchW, int SimilW, float h, float lambda)
+ {
+ int SimilW_full, count, i, j, k, i_n, j_n, k_n, i_m, j_m, k_m, i_p, j_p, k_p, i_l, j_l, k_l, i1, j1, k1, i2, j2, k2, i3, j3, k3, i5, j5, k5;
+ float *Eucl_Vec, h2, denh2, normsum, Weight, Weight_norm, value, denom, WeightGlob;
+
+ /*SearchW_full = 2*SearchW + 1; */ /* the full searching window size */
+ SimilW_full = 2*SimilW + 1; /* the full similarity window size */
+ h2 = h*h;
+ denh2 = 1/(2*h2);
+
+ /*Gaussian kernel */
+ Eucl_Vec = (float*) calloc (SimilW_full*SimilW_full*SimilW_full,sizeof(float));
+ count = 0;
+ for(i_n=-SimilW; i_n<=SimilW; i_n++) {
+ for(j_n=-SimilW; j_n<=SimilW; j_n++) {
+ for(k_n=-SimilW; k_n<=SimilW; k_n++) {
+ Eucl_Vec[count] = exp(-(pow((float)i_n, 2) + pow((float)j_n, 2) + pow((float)k_n, 2))/(2*SimilW*SimilW*SimilW));
+ count = count + 1;
+ }}} /*main neighb loop */
+
+ /*The NLM code starts here*/
+ /* setting OMP here */
+ #pragma omp parallel for shared (A, B, dimX, dimY, dimZ, Eucl_Vec, lambda, denh2) private(denom, i, j, k, WeightGlob,count, i1, j1, k1, i2, j2, k2, i3, j3, k3, i5, j5, k5, Weight_norm, normsum, i_m, j_m, k_m, i_n, j_n, k_n, i_l, j_l, k_l, i_p, j_p, k_p, Weight, value)
+ for(i=0; i<dimX; i++) {
+ for(j=0; j<dimY; j++) {
+ for(k=0; k<dimZ; k++) {
+ if (((i >= padXY) && (i < dimX-padXY)) && ((j >= padXY) && (j < dimY-padXY)) && ((k >= padXY) && (k < dimZ-padXY))) {
+ /* take all elements around the pixel of interest */
+ /* Massive Search window loop */
+ Weight_norm = 0; value = 0.0;
+ for(i_m=-SearchW; i_m<=SearchW; i_m++) {
+ for(j_m=-SearchW; j_m<=SearchW; j_m++) {
+ for(k_m=-SearchW; k_m<=SearchW; k_m++) {
+ /*checking boundaries*/
+ i1 = i+i_m; j1 = j+j_m; k1 = k+k_m;
+
+ WeightGlob = 0.0;
+ /* if inside the searching window */
+ for(i_l=-SimilW; i_l<=SimilW; i_l++) {
+ for(j_l=-SimilW; j_l<=SimilW; j_l++) {
+ for(k_l=-SimilW; k_l<=SimilW; k_l++) {
+ i2 = i1+i_l; j2 = j1+j_l; k2 = k1+k_l;
+
+ i3 = i+i_l; j3 = j+j_l; k3 = k+k_l; /*coordinates of the inner patch loop */
+
+ count = 0; normsum = 0.0;
+ for(i_p=-SimilW; i_p<=SimilW; i_p++) {
+ for(j_p=-SimilW; j_p<=SimilW; j_p++) {
+ for(k_p=-SimilW; k_p<=SimilW; k_p++) {
+ i5 = i2 + i_p; j5 = j2 + j_p; k5 = k2 + k_p;
+ normsum = normsum + Eucl_Vec[count]*pow(A[(dimX*dimY)*(k3+k_p)+(i3+i_p)*dimY+(j3+j_p)]-A[(dimX*dimY)*k5 + i5*dimY+j5], 2);
+ count = count + 1;
+ }}}
+ if (normsum != 0) Weight = (exp(-normsum*denh2));
+ else Weight = 0.0;
+ WeightGlob += Weight;
+ }}}
+ value += A[(dimX*dimY)*k1 + i1*dimY+j1]*WeightGlob;
+ Weight_norm += WeightGlob;
+
+ }}} /*search window loop end*/
+
+ /* the final loop to average all values in searching window with weights */
+ denom = 1 + lambda*Weight_norm;
+ B[(dimX*dimY)*k + i*dimY+j] = (A[(dimX*dimY)*k + i*dimY+j] + lambda*value)/denom;
+ }
+ }}} /*main loop*/
+ free(Eucl_Vec);
+ return *B;
+}
+
+float pad_crop(float *A, float *Ap, int OldSizeX, int OldSizeY, int OldSizeZ, int NewSizeX, int NewSizeY, int NewSizeZ, int padXY, int switchpad_crop)
+{
+ /* padding-cropping function */
+ int i,j,k;
+ if (NewSizeZ > 1) {
+ for (i=0; i < NewSizeX; i++) {
+ for (j=0; j < NewSizeY; j++) {
+ for (k=0; k < NewSizeZ; k++) {
+ if (((i >= padXY) && (i < NewSizeX-padXY)) && ((j >= padXY) && (j < NewSizeY-padXY)) && ((k >= padXY) && (k < NewSizeZ-padXY))) {
+ if (switchpad_crop == 0) Ap[NewSizeX*NewSizeY*k + i*NewSizeY+j] = A[OldSizeX*OldSizeY*(k - padXY) + (i-padXY)*(OldSizeY)+(j-padXY)];
+ else Ap[OldSizeX*OldSizeY*(k - padXY) + (i-padXY)*(OldSizeY)+(j-padXY)] = A[NewSizeX*NewSizeY*k + i*NewSizeY+j];
+ }
+ }}}
+ }
+ else {
+ for (i=0; i < NewSizeX; i++) {
+ for (j=0; j < NewSizeY; j++) {
+ if (((i >= padXY) && (i < NewSizeX-padXY)) && ((j >= padXY) && (j < NewSizeY-padXY))) {
+ if (switchpad_crop == 0) Ap[i*NewSizeY+j] = A[(i-padXY)*(OldSizeY)+(j-padXY)];
+ else Ap[(i-padXY)*(OldSizeY)+(j-padXY)] = A[i*NewSizeY+j];
+ }
+ }}
+ }
+ return *Ap;
+} \ No newline at end of file
diff --git a/main_func/SplitBregman_TV.c b/main_func/regularizers_CPU/SplitBregman_TV.c
index f143aa6..f143aa6 100644
--- a/main_func/SplitBregman_TV.c
+++ b/main_func/regularizers_CPU/SplitBregman_TV.c
diff --git a/main_func/regularizers_CPU/TGV_PD.c b/main_func/regularizers_CPU/TGV_PD.c
new file mode 100644
index 0000000..41f8615
--- /dev/null
+++ b/main_func/regularizers_CPU/TGV_PD.c
@@ -0,0 +1,353 @@
+#include "mex.h"
+#include <matrix.h>
+#include <math.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <stdio.h>
+#include "omp.h"
+
+/* C-OMP implementation of Primal-Dual denoising method for
+ * Total Generilized Variation (TGV)-L2 model (2D case only)
+ *
+ * Input Parameters:
+ * 1. Noisy image/volume (2D)
+ * 2. lambda - regularization parameter
+ * 3. parameter to control first-order term (alpha1)
+ * 4. parameter to control the second-order term (alpha0)
+ * 5. Number of CP iterations
+ *
+ * Output:
+ * Filtered/regularized image
+ *
+ * Example:
+ * figure;
+ * Im = double(imread('lena_gray_256.tif'))/255; % loading image
+ * u0 = Im + .03*randn(size(Im)); % adding noise
+ * tic; u = PrimalDual_TGV(single(u0), 0.02, 1.3, 1, 550); toc;
+ *
+ * to compile with OMP support: mex TGV_PD.c CFLAGS="\$CFLAGS -fopenmp -Wall -std=c99" LDFLAGS="\$LDFLAGS -fopenmp"
+ * References:
+ * K. Bredies "Total Generalized Variation"
+ *
+ * 28.11.16/Harwell
+ */
+
+/* 2D functions */
+float DualP_2D(float *U, float *V1, float *V2, float *P1, float *P2, int dimX, int dimY, int dimZ, float sigma);
+float ProjP_2D(float *P1, float *P2, int dimX, int dimY, int dimZ, float alpha1);
+float DualQ_2D(float *V1, float *V2, float *Q1, float *Q2, float *Q3, int dimX, int dimY, int dimZ, float sigma);
+float ProjQ_2D(float *Q1, float *Q2, float *Q3, int dimX, int dimY, int dimZ, float alpha0);
+float DivProjP_2D(float *U, float *A, float *P1, float *P2, int dimX, int dimY, int dimZ, float lambda, float tau);
+float UpdV_2D(float *V1, float *V2, float *P1, float *P2, float *Q1, float *Q2, float *Q3, int dimX, int dimY, int dimZ, float tau);
+/*3D functions*/
+float DualP_3D(float *U, float *V1, float *V2, float *V3, float *P1, float *P2, float *P3, int dimX, int dimY, int dimZ, float sigma);
+
+float newU(float *U, float *U_old, int dimX, int dimY, int dimZ);
+float copyIm(float *A, float *U, int dimX, int dimY, int dimZ);
+
+void mexFunction(
+ int nlhs, mxArray *plhs[],
+ int nrhs, const mxArray *prhs[])
+
+{
+ int number_of_dims, iter, dimX, dimY, dimZ, ll;
+ const int *dim_array;
+ float *A, *U, *U_old, *P1, *P2, *P3, *Q1, *Q2, *Q3, *Q4, *Q5, *Q6, *Q7, *Q8, *Q9, *V1, *V1_old, *V2, *V2_old, *V3, *V3_old, lambda, L2, tau, sigma, alpha1, alpha0;
+
+ number_of_dims = mxGetNumberOfDimensions(prhs[0]);
+ dim_array = mxGetDimensions(prhs[0]);
+
+ /*Handling Matlab input data*/
+ A = (float *) mxGetData(prhs[0]); /*origanal noise image/volume*/
+ if (mxGetClassID(prhs[0]) != mxSINGLE_CLASS) {mexErrMsgTxt("The input in single precision is required"); }
+ lambda = (float) mxGetScalar(prhs[1]); /*regularization parameter*/
+ alpha1 = (float) mxGetScalar(prhs[2]); /*first-order term*/
+ alpha0 = (float) mxGetScalar(prhs[3]); /*second-order term*/
+ iter = (int) mxGetScalar(prhs[4]); /*iterations number*/
+ if(nrhs != 5) mexErrMsgTxt("Five input parameters is reqired: Image(2D/3D), Regularization parameter, alpha1, alpha0, Iterations");
+
+ /*Handling Matlab output data*/
+ dimX = dim_array[0]; dimY = dim_array[1];
+
+ if (number_of_dims == 2) {
+ /*2D case*/
+ dimZ = 1;
+ U = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));
+
+ /*dual variables*/
+ P1 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));
+ P2 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));
+
+ Q1 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));
+ Q2 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));
+ Q3 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));
+
+ U_old = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));
+
+ V1 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));
+ V1_old = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));
+ V2 = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL));
+ V2_old = (float*)mxGetPr(mxCreateNumericArray(2, dim_array, mxSINGLE_CLASS, mxREAL)); }
+ else if (number_of_dims == 3) {
+ mexErrMsgTxt("The input data should be 2D");
+ /*3D case*/
+// dimZ = dim_array[2];
+// U = (float*)mxGetPr(plhs[0] = mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+//
+// P1 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// P2 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// P3 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+//
+// Q1 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// Q2 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// Q3 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// Q4 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// Q5 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// Q6 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// Q7 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// Q8 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// Q9 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+//
+// U_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+//
+// V1 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// V1_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// V2 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// V2_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// V3 = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+// V3_old = (float*)mxGetPr(mxCreateNumericArray(3, dim_array, mxSINGLE_CLASS, mxREAL));
+ }
+ else {mexErrMsgTxt("The input data should be 2D");}
+
+
+ /*printf("%i \n", i);*/
+ L2 = 12.0; /*Lipshitz constant*/
+ tau = 1.0/pow(L2,0.5);
+ sigma = 1.0/pow(L2,0.5);
+
+ /*Copy A to U*/
+ copyIm(A, U, dimX, dimY, dimZ);
+
+ if (number_of_dims == 2) {
+ /* Here primal-dual iterations begin for 2D */
+ for(ll = 0; ll < iter; ll++) {
+
+ /* Calculate Dual Variable P */
+ DualP_2D(U, V1, V2, P1, P2, dimX, dimY, dimZ, sigma);
+
+ /*Projection onto convex set for P*/
+ ProjP_2D(P1, P2, dimX, dimY, dimZ, alpha1);
+
+ /* Calculate Dual Variable Q */
+ DualQ_2D(V1, V2, Q1, Q2, Q3, dimX, dimY, dimZ, sigma);
+
+ /*Projection onto convex set for Q*/
+ ProjQ_2D(Q1, Q2, Q3, dimX, dimY, dimZ, alpha0);
+
+ /*saving U into U_old*/
+ copyIm(U, U_old, dimX, dimY, dimZ);
+
+ /*adjoint operation -> divergence and projection of P*/
+ DivProjP_2D(U, A, P1, P2, dimX, dimY, dimZ, lambda, tau);
+
+ /*get updated solution U*/
+ newU(U, U_old, dimX, dimY, dimZ);
+
+ /*saving V into V_old*/
+ copyIm(V1, V1_old, dimX, dimY, dimZ);
+ copyIm(V2, V2_old, dimX, dimY, dimZ);
+
+ /* upd V*/
+ UpdV_2D(V1, V2, P1, P2, Q1, Q2, Q3, dimX, dimY, dimZ, tau);
+
+ /*get new V*/
+ newU(V1, V1_old, dimX, dimY, dimZ);
+ newU(V2, V2_old, dimX, dimY, dimZ);
+ } /*end of iterations*/
+ }
+
+// /*3D version*/
+// if (number_of_dims == 3) {
+// /* Here primal-dual iterations begin for 3D */
+// for(ll = 0; ll < iter; ll++) {
+//
+// /* Calculate Dual Variable P */
+// DualP_3D(U, V1, V2, V3, P1, P2, P3, dimX, dimY, dimZ, sigma);
+//
+// /*Projection onto convex set for P*/
+// ProjP_3D(P1, P2, P3, dimX, dimY, dimZ, alpha1);
+//
+// /* Calculate Dual Variable Q */
+// DualQ_3D(V1, V2, V2, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, dimX, dimY, dimZ, sigma);
+//
+// } /*end of iterations*/
+// }
+}
+
+/*Calculating dual variable P (using forward differences)*/
+float DualP_2D(float *U, float *V1, float *V2, float *P1, float *P2, int dimX, int dimY, int dimZ, float sigma)
+{
+ int i,j;
+#pragma omp parallel for shared(U,V1,V2,P1,P2) private(i,j)
+ for(i=0; i<dimX; i++) {
+ for(j=0; j<dimY; j++) {
+ /* symmetric boundary conditions (Neuman) */
+ if (i == dimX-1) P1[i*dimY + (j)] = P1[i*dimY + (j)] + sigma*((U[(i-1)*dimY + (j)] - U[i*dimY + (j)]) - V1[i*dimY + (j)]);
+ else P1[i*dimY + (j)] = P1[i*dimY + (j)] + sigma*((U[(i + 1)*dimY + (j)] - U[i*dimY + (j)]) - V1[i*dimY + (j)]);
+ if (j == dimY-1) P2[i*dimY + (j)] = P2[i*dimY + (j)] + sigma*((U[(i)*dimY + (j-1)] - U[i*dimY + (j)]) - V2[i*dimY + (j)]);
+ else P2[i*dimY + (j)] = P2[i*dimY + (j)] + sigma*((U[(i)*dimY + (j+1)] - U[i*dimY + (j)]) - V2[i*dimY + (j)]);
+ }}
+ return 1;
+}
+/*Projection onto convex set for P*/
+float ProjP_2D(float *P1, float *P2, int dimX, int dimY, int dimZ, float alpha1)
+{
+ float grad_magn;
+ int i,j;
+#pragma omp parallel for shared(P1,P2) private(i,j,grad_magn)
+ for(i=0; i<dimX; i++) {
+ for(j=0; j<dimY; j++) {
+ grad_magn = sqrt(pow(P1[i*dimY + (j)],2) + pow(P2[i*dimY + (j)],2));
+ grad_magn = grad_magn/alpha1;
+ if (grad_magn > 1.0) {
+ P1[i*dimY + (j)] = P1[i*dimY + (j)]/grad_magn;
+ P2[i*dimY + (j)] = P2[i*dimY + (j)]/grad_magn;
+ }
+ }}
+ return 1;
+}
+/*Calculating dual variable Q (using forward differences)*/
+float DualQ_2D(float *V1, float *V2, float *Q1, float *Q2, float *Q3, int dimX, int dimY, int dimZ, float sigma)
+{
+ int i,j;
+ float q1, q2, q11, q22;
+#pragma omp parallel for shared(Q1,Q2,Q3,V1,V2) private(i,j,q1,q2,q11,q22)
+ for(i=0; i<dimX; i++) {
+ for(j=0; j<dimY; j++) {
+ /* symmetric boundary conditions (Neuman) */
+ if (i == dimX-1)
+ { q1 = (V1[(i-1)*dimY + (j)] - V1[i*dimY + (j)]);
+ q11 = (V2[(i-1)*dimY + (j)] - V2[i*dimY + (j)]);
+ }
+ else {
+ q1 = (V1[(i+1)*dimY + (j)] - V1[i*dimY + (j)]);
+ q11 = (V2[(i+1)*dimY + (j)] - V2[i*dimY + (j)]);
+ }
+ if (j == dimY-1) {
+ q2 = (V2[(i)*dimY + (j-1)] - V2[i*dimY + (j)]);
+ q22 = (V1[(i)*dimY + (j-1)] - V1[i*dimY + (j)]);
+ }
+ else {
+ q2 = (V2[(i)*dimY + (j+1)] - V2[i*dimY + (j)]);
+ q22 = (V1[(i)*dimY + (j+1)] - V1[i*dimY + (j)]);
+ }
+ Q1[i*dimY + (j)] = Q1[i*dimY + (j)] + sigma*(q1);
+ Q2[i*dimY + (j)] = Q2[i*dimY + (j)] + sigma*(q2);
+ Q3[i*dimY + (j)] = Q3[i*dimY + (j)] + sigma*(0.5f*(q11 + q22));
+ }}
+ return 1;
+}
+
+float ProjQ_2D(float *Q1, float *Q2, float *Q3, int dimX, int dimY, int dimZ, float alpha0)
+{
+ float grad_magn;
+ int i,j;
+#pragma omp parallel for shared(Q1,Q2,Q3) private(i,j,grad_magn)
+ for(i=0; i<dimX; i++) {
+ for(j=0; j<dimY; j++) {
+ grad_magn = sqrt(pow(Q1[i*dimY + (j)],2) + pow(Q2[i*dimY + (j)],2) + 2*pow(Q3[i*dimY + (j)],2));
+ grad_magn = grad_magn/alpha0;
+ if (grad_magn > 1.0) {
+ Q1[i*dimY + (j)] = Q1[i*dimY + (j)]/grad_magn;
+ Q2[i*dimY + (j)] = Q2[i*dimY + (j)]/grad_magn;
+ Q3[i*dimY + (j)] = Q3[i*dimY + (j)]/grad_magn;
+ }
+ }}
+ return 1;
+}
+/* Divergence and projection for P*/
+float DivProjP_2D(float *U, float *A, float *P1, float *P2, int dimX, int dimY, int dimZ, float lambda, float tau)
+{
+ int i,j;
+ float P_v1, P_v2, div;
+#pragma omp parallel for shared(U,A,P1,P2) private(i,j,P_v1,P_v2,div)
+ for(i=0; i<dimX; i++) {
+ for(j=0; j<dimY; j++) {
+ if (i == 0) P_v1 = (P1[i*dimY + (j)]);
+ else P_v1 = (P1[i*dimY + (j)] - P1[(i-1)*dimY + (j)]);
+ if (j == 0) P_v2 = (P2[i*dimY + (j)]);
+ else P_v2 = (P2[i*dimY + (j)] - P2[(i)*dimY + (j-1)]);
+ div = P_v1 + P_v2;
+ U[i*dimY + (j)] = (lambda*(U[i*dimY + (j)] + tau*div) + tau*A[i*dimY + (j)])/(lambda + tau);
+ }}
+ return *U;
+}
+/*get updated solution U*/
+float newU(float *U, float *U_old, int dimX, int dimY, int dimZ)
+{
+ int i;
+#pragma omp parallel for shared(U,U_old) private(i)
+ for(i=0; i<dimX*dimY*dimZ; i++) U[i] = 2*U[i] - U_old[i];
+ return *U;
+}
+
+/*get update for V*/
+float UpdV_2D(float *V1, float *V2, float *P1, float *P2, float *Q1, float *Q2, float *Q3, int dimX, int dimY, int dimZ, float tau)
+{
+ int i,j;
+ float q1, q11, q2, q22, div1, div2;
+#pragma omp parallel for shared(V1,V2,P1,P2,Q1,Q2,Q3) private(i,j, q1, q11, q2, q22, div1, div2)
+ for(i=0; i<dimX; i++) {
+ for(j=0; j<dimY; j++) {
+ /* symmetric boundary conditions (Neuman) */
+ if (i == 0) {
+ q1 = (Q1[i*dimY + (j)]);
+ q11 = (Q3[i*dimY + (j)]);
+ }
+ else {
+ q1 = (Q1[i*dimY + (j)] - Q1[(i-1)*dimY + (j)]);
+ q11 = (Q3[i*dimY + (j)] - Q3[(i-1)*dimY + (j)]);
+ }
+ if (j == 0) {
+ q2 = (Q2[i*dimY + (j)]);
+ q22 = (Q3[i*dimY + (j)]);
+ }
+ else {
+ q2 = (Q2[i*dimY + (j)] - Q2[(i)*dimY + (j-1)]);
+ q22 = (Q3[i*dimY + (j)] - Q3[(i)*dimY + (j-1)]);
+ }
+ div1 = q1 + q22;
+ div2 = q2 + q11;
+ V1[i*dimY + (j)] = V1[i*dimY + (j)] + tau*(P1[i*dimY + (j)] + div1);
+ V2[i*dimY + (j)] = V2[i*dimY + (j)] + tau*(P2[i*dimY + (j)] + div2);
+ }}
+ return 1;
+}
+/* Copy Image */
+float copyIm(float *A, float *U, int dimX, int dimY, int dimZ)
+{
+ int j;
+#pragma omp parallel for shared(A, U) private(j)
+ for(j=0; j<dimX*dimY*dimZ; j++) U[j] = A[j];
+ return *U;
+}
+/*********************3D *********************/
+
+/*Calculating dual variable P (using forward differences)*/
+float DualP_3D(float *U, float *V1, float *V2, float *V3, float *P1, float *P2, float *P3, int dimX, int dimY, int dimZ, float sigma)
+{
+ int i,j,k;
+#pragma omp parallel for shared(U,V1,V2,V3,P1,P2,P3) private(i,j,k)
+ for(i=0; i<dimX; i++) {
+ for(j=0; j<dimY; j++) {
+ for(k=0; k<dimZ; k++) {
+ /* symmetric boundary conditions (Neuman) */
+ if (i == dimX-1) P1[dimX*dimY*k + i*dimY + (j)] = P1[dimX*dimY*k + i*dimY + (j)] + sigma*((U[dimX*dimY*k + (i-1)*dimY + (j)] - U[dimX*dimY*k + i*dimY + (j)]) - V1[dimX*dimY*k + i*dimY + (j)]);
+ else P1[dimX*dimY*k + i*dimY + (j)] = P1[dimX*dimY*k + i*dimY + (j)] + sigma*((U[dimX*dimY*k + (i + 1)*dimY + (j)] - U[dimX*dimY*k + i*dimY + (j)]) - V1[dimX*dimY*k + i*dimY + (j)]);
+ if (j == dimY-1) P2[dimX*dimY*k + i*dimY + (j)] = P2[dimX*dimY*k + i*dimY + (j)] + sigma*((U[dimX*dimY*k + (i)*dimY + (j-1)] - U[dimX*dimY*k + i*dimY + (j)]) - V2[dimX*dimY*k + i*dimY + (j)]);
+ else P2[dimX*dimY*k + i*dimY + (j)] = P2[dimX*dimY*k + i*dimY + (j)] + sigma*((U[dimX*dimY*k + (i)*dimY + (j+1)] - U[dimX*dimY*k + i*dimY + (j)]) - V2[dimX*dimY*k + i*dimY + (j)]);
+ if (k == dimZ-1) P3[dimX*dimY*k + i*dimY + (j)] = P3[dimX*dimY*k + i*dimY + (j)] + sigma*((U[dimX*dimY*(k-1) + (i)*dimY + (j)] - U[dimX*dimY*k + i*dimY + (j)]) - V3[dimX*dimY*k + i*dimY + (j)]);
+ else P3[dimX*dimY*k + i*dimY + (j)] = P3[dimX*dimY*k + i*dimY + (j)] + sigma*((U[dimX*dimY*(k+1) + (i)*dimY + (j)] - U[dimX*dimY*k + i*dimY + (j)]) - V3[dimX*dimY*k + i*dimY + (j)]);
+ }}}
+ return 1;
+} \ No newline at end of file