From 1cc67c1e4d9b6b24c096f52d6f086a3f224ece8a Mon Sep 17 00:00:00 2001
From: Willem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>
Date: Wed, 7 Oct 2015 17:29:20 +0200
Subject: Add astra_mex_direct('FP3D'/'BP3D', ...)

---
 build/linux/Makefile.in           |   3 +-
 matlab/mex/astra_mex_direct_c.cpp | 332 ++++++++++++++++++++++++++++++++++++++
 matlab/tools/astra_mex_direct.m   |  24 +++
 3 files changed, 358 insertions(+), 1 deletion(-)
 create mode 100755 matlab/mex/astra_mex_direct_c.cpp
 create mode 100644 matlab/tools/astra_mex_direct.m

diff --git a/build/linux/Makefile.in b/build/linux/Makefile.in
index 2d862f2..abbebe2 100644
--- a/build/linux/Makefile.in
+++ b/build/linux/Makefile.in
@@ -232,7 +232,8 @@ MATLAB_MEX=\
 	matlab/mex/astra_mex_projector_c.$(MEXSUFFIX) \
 	matlab/mex/astra_mex_projector3d_c.$(MEXSUFFIX) \
 	matlab/mex/astra_mex_log_c.$(MEXSUFFIX) \
-	matlab/mex/astra_mex_data3d_c.$(MEXSUFFIX)
+	matlab/mex/astra_mex_data3d_c.$(MEXSUFFIX) \
+	matlab/mex/astra_mex_direct_c.$(MEXSUFFIX)
 
 
 OBJECT_DIRS = src/ tests/ cuda/2d/ cuda/3d/ matlab/mex/ ./
diff --git a/matlab/mex/astra_mex_direct_c.cpp b/matlab/mex/astra_mex_direct_c.cpp
new file mode 100755
index 0000000..94eb1cd
--- /dev/null
+++ b/matlab/mex/astra_mex_direct_c.cpp
@@ -0,0 +1,332 @@
+/*
+-----------------------------------------------------------------------
+Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+           2014-2015, CWI, Amsterdam
+
+Contact: astra@uantwerpen.be
+Website: http://sf.net/projects/astra-toolbox
+
+This file is part of the ASTRA Toolbox.
+
+
+The ASTRA Toolbox is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+The ASTRA Toolbox is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+/** \file astra_mex_direct_c.cpp
+ *
+ *  \brief Utility functions for low-overhead FP and BP calls.
+ */
+#include <mex.h>
+#include "mexHelpFunctions.h"
+#include "mexCopyDataHelpFunctions.h"
+#include "mexDataManagerHelpFunctions.h"
+
+#include <list>
+
+#include "astra/Globals.h"
+
+#include "astra/AstraObjectManager.h"
+
+#include "astra/Float32ProjectionData2D.h"
+#include "astra/Float32VolumeData2D.h"
+#include "astra/CudaProjector3D.h"
+#include "astra/Projector3D.h"
+#include "astra/Float32ProjectionData3DMemory.h"
+#include "astra/Float32VolumeData3DMemory.h"
+
+#include "astra/CudaForwardProjectionAlgorithm3D.h"
+
+#include "astra/CudaBackProjectionAlgorithm3D.h"
+
+using namespace std;
+using namespace astra;
+
+#define USE_MATLAB_UNDOCUMENTED
+
+
+class CFloat32CustomMemory_simple : public astra::CFloat32CustomMemory {
+public:
+	CFloat32CustomMemory_simple(float *ptr) { m_fPtr = ptr; }
+	~CFloat32CustomMemory_simple() { }
+};
+
+#ifdef ASTRA_CUDA
+
+//-----------------------------------------------------------------------------------------
+/**
+ * projection = astra_mex_direct_c('FP3D', projector_id, volume);
+ * Both 'projection' and 'volume' are Matlab arrays.
+ */
+void astra_mex_direct_fp3d(int& nlhs, mxArray* plhs[], int& nrhs, const mxArray* prhs[])
+{
+	// TODO: Add an optional way of specifying extra options
+
+	if (nrhs < 3) {
+		mexErrMsgTxt("Not enough arguments. Syntax: astra_mex_direct_c('FP3D', projector_id, data)");
+		return;
+	}
+
+	int iPid = (int)(mxGetScalar(prhs[1]));
+	astra::CProjector3D* pProjector;
+	pProjector = astra::CProjector3DManager::getSingleton().get(iPid);
+	if (!pProjector) {
+		mexErrMsgTxt("Projector not found.");
+		return;
+	}
+	if (!pProjector->isInitialized()) {
+		mexErrMsgTxt("Projector not initialized.");
+		return;
+	}
+	bool isCuda = false;
+	if (dynamic_cast<CCudaProjector3D*>(pProjector))
+		isCuda = true;
+	if (!isCuda) {
+		mexErrMsgTxt("Only CUDA projectors are currently supported.");
+		return;
+	}
+
+	astra::CVolumeGeometry3D* pVolGeom = pProjector->getVolumeGeometry();
+	astra::CProjectionGeometry3D* pProjGeom = pProjector->getProjectionGeometry();
+
+	const mxArray* const data = prhs[2];
+	if (!checkDataType(data)) {
+		mexErrMsgTxt("Data must be single or double.");
+		return;
+	}
+
+	if (!checkDataSize(data, pVolGeom)) {
+		mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry.");
+		return;
+	}
+
+
+	// Allocate input data
+	astra::CFloat32VolumeData3DMemory* pInput;
+	if (mxIsSingle(data)) {
+		astra::CFloat32CustomMemory* m = new CFloat32CustomMemory_simple((float *)mxGetData(data));
+		pInput = new astra::CFloat32VolumeData3DMemory(pVolGeom, m);
+	} else {
+		pInput = new astra::CFloat32VolumeData3DMemory(pVolGeom);
+		copyMexToCFloat32Array(data, pInput->getData(), pInput->getSize());
+	}
+
+
+	// Allocate output data
+	// If the input is single, we also allocate single output.
+	// Otherwise, double.
+	astra::CFloat32ProjectionData3DMemory* pOutput;
+	mxArray *pOutputMx;
+	if (mxIsSingle(data)) {
+		mwSize dims[3];
+		dims[0] = pProjGeom->getDetectorColCount();
+		dims[1] = pProjGeom->getProjectionCount();
+		dims[2] = pProjGeom->getDetectorRowCount();
+		pOutputMx = mxCreateNumericArray(3, dims, mxSINGLE_CLASS, mxREAL);
+
+		astra::CFloat32CustomMemory* m = new CFloat32CustomMemory_simple((float *)mxGetData(pOutputMx));
+		pOutput = new astra::CFloat32ProjectionData3DMemory(pProjGeom, m);
+	} else {
+		pOutput = new astra::CFloat32ProjectionData3DMemory(pProjGeom);
+	}
+
+	// Perform FP
+
+	astra::CCudaForwardProjectionAlgorithm3D* pAlg;
+	pAlg = new astra::CCudaForwardProjectionAlgorithm3D();
+	pAlg->initialize(pProjector, pOutput, pInput);
+
+	if (!pAlg->isInitialized()) {
+		mexErrMsgTxt("Error initializing algorithm.");
+		// TODO: Delete pOutputMx?
+		delete pAlg;
+		delete pInput;
+		delete pOutput;
+		return;
+	}
+
+	pAlg->run();
+
+	delete pAlg;
+
+
+	if (mxIsSingle(data)) {
+
+	} else {
+		pOutputMx = createEquivMexArray<mxDOUBLE_CLASS>(pOutput);
+		copyCFloat32ArrayToMex(pOutput->getData(), pOutputMx);
+	}
+	plhs[0] = pOutputMx;
+
+	delete pOutput;
+	delete pInput;
+}
+//-----------------------------------------------------------------------------------------
+/**
+ * projection = astra_mex_direct_c('BP3D', projector_id, volume);
+ * Both 'projection' and 'volume' are Matlab arrays.
+ */
+void astra_mex_direct_bp3d(int& nlhs, mxArray* plhs[], int& nrhs, const mxArray* prhs[])
+{
+	// TODO: Add an optional way of specifying extra options
+
+	if (nrhs < 3) {
+		mexErrMsgTxt("Not enough arguments. Syntax: astra_mex_direct_c('BP3D', projector_id, data)");
+		return;
+	}
+
+	int iPid = (int)(mxGetScalar(prhs[1]));
+	astra::CProjector3D* pProjector;
+	pProjector = astra::CProjector3DManager::getSingleton().get(iPid);
+	if (!pProjector) {
+		mexErrMsgTxt("Projector not found.");
+		return;
+	}
+	if (!pProjector->isInitialized()) {
+		mexErrMsgTxt("Projector not initialized.");
+		return;
+	}
+	bool isCuda = false;
+	if (dynamic_cast<CCudaProjector3D*>(pProjector))
+		isCuda = true;
+	if (!isCuda) {
+		mexErrMsgTxt("Only CUDA projectors are currently supported.");
+		return;
+	}
+
+	astra::CVolumeGeometry3D* pVolGeom = pProjector->getVolumeGeometry();
+	astra::CProjectionGeometry3D* pProjGeom = pProjector->getProjectionGeometry();
+
+	const mxArray* const data = prhs[2];
+	if (!checkDataType(data)) {
+		mexErrMsgTxt("Data must be single or double.");
+		return;
+	}
+
+	if (!checkDataSize(data, pProjGeom)) {
+		mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry.");
+		return;
+	}
+
+
+	// Allocate input data
+	astra::CFloat32ProjectionData3DMemory* pInput;
+	if (mxIsSingle(data)) {
+		astra::CFloat32CustomMemory* m = new CFloat32CustomMemory_simple((float *)mxGetData(data));
+		pInput = new astra::CFloat32ProjectionData3DMemory(pProjGeom, m);
+	} else {
+		pInput = new astra::CFloat32ProjectionData3DMemory(pProjGeom);
+		copyMexToCFloat32Array(data, pInput->getData(), pInput->getSize());
+	}
+
+
+	// Allocate output data
+	// If the input is single, we also allocate single output.
+	// Otherwise, double.
+	astra::CFloat32VolumeData3DMemory* pOutput;
+	mxArray *pOutputMx;
+	if (mxIsSingle(data)) {
+		mwSize dims[3];
+		dims[0] = pVolGeom->getGridColCount();
+		dims[1] = pVolGeom->getGridRowCount();
+		dims[2] = pVolGeom->getGridSliceCount();
+		pOutputMx = mxCreateNumericArray(3, dims, mxSINGLE_CLASS, mxREAL);
+
+		astra::CFloat32CustomMemory* m = new CFloat32CustomMemory_simple((float *)mxGetData(pOutputMx));
+		pOutput = new astra::CFloat32VolumeData3DMemory(pVolGeom, m);
+	} else {
+		pOutput = new astra::CFloat32VolumeData3DMemory(pVolGeom);
+	}
+
+	// Perform BP
+
+	astra::CCudaBackProjectionAlgorithm3D* pAlg;
+	pAlg = new astra::CCudaBackProjectionAlgorithm3D();
+	pAlg->initialize(pProjector, pInput, pOutput);
+
+	if (!pAlg->isInitialized()) {
+		mexErrMsgTxt("Error initializing algorithm.");
+		// TODO: Delete pOutputMx?
+		delete pAlg;
+		delete pInput;
+		delete pOutput;
+		return;
+	}
+
+	pAlg->run();
+
+	delete pAlg;
+
+
+	if (mxIsSingle(data)) {
+
+	} else {
+		pOutputMx = createEquivMexArray<mxDOUBLE_CLASS>(pOutput);
+		copyCFloat32ArrayToMex(pOutput->getData(), pOutputMx);
+	}
+	plhs[0] = pOutputMx;
+
+	delete pOutput;
+	delete pInput;
+}
+
+#endif
+
+//-----------------------------------------------------------------------------------------
+
+static void printHelp()
+{
+	mexPrintf("Please specify a mode of operation.\n");
+	mexPrintf("Valid modes: FP3D, BP3D\n");
+}
+
+
+//-----------------------------------------------------------------------------------------
+/**
+ * ... = astra_mex_direct_c(mode,...);
+ */
+void mexFunction(int nlhs, mxArray* plhs[],
+				 int nrhs, const mxArray* prhs[])
+{
+
+	// INPUT: Mode
+	string sMode;
+	if (1 <= nrhs) {
+		sMode = mexToString(prhs[0]);
+	} else {
+		printHelp();
+		return;
+	}
+
+#ifndef ASTRA_CUDA
+	mexErrMsgTxt("Only CUDA projectors are currently supported.");
+	return;
+#else
+
+	// 3D data
+	if (sMode == "FP3D") {
+		astra_mex_direct_fp3d(nlhs, plhs, nrhs, prhs);
+	} else if (sMode == "BP3D") {
+		astra_mex_direct_bp3d(nlhs, plhs, nrhs, prhs);
+	} else {
+		printHelp();
+	}
+#endif
+
+	return;
+}
+
+
diff --git a/matlab/tools/astra_mex_direct.m b/matlab/tools/astra_mex_direct.m
new file mode 100644
index 0000000..58c4fd2
--- /dev/null
+++ b/matlab/tools/astra_mex_direct.m
@@ -0,0 +1,24 @@
+function [varargout] = astra_mex_direct(varargin)
+%------------------------------------------------------------------------
+% Reference page in Help browser
+%    <a href="matlab:docsearch('astra_mex_direct' )">astra_mex_data3d</a>.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the ASTRA Toolbox
+% 
+% Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+%            2014-2015, CWI, Amsterdam
+% License: Open Source under GPLv3
+% Contact: astra@uantwerpen.be
+% Website: http://sf.net/projects/astra-toolbox
+%------------------------------------------------------------------------
+% $Id$
+if nargout == 0
+    astra_mex_direct_c(varargin{:});
+    if exist('ans','var')
+        varargout{1} = ans;
+    end
+else
+    varargout = cell(1,nargout);
+    [varargout{:}] = astra_mex_direct_c(varargin{:});
+end
-- 
cgit v1.2.3