/*
-----------------------------------------------------------------------
Copyright: 2010-2021, imec Vision Lab, University of Antwerp
2014-2021, CWI, Amsterdam
Contact: astra@astra-toolbox.com
Website: http://www.astra-toolbox.com/
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 .
-----------------------------------------------------------------------
*/
/** \file astra_mex_data3d_c.cpp
*
* \brief Creates, manages and manipulates 3D volume and projection data objects.
*/
#include
#include "mexHelpFunctions.h"
#include "mexInitFunctions.h"
#include "mexCopyDataHelpFunctions.h"
#include "mexDataManagerHelpFunctions.h"
#include
#include "astra/Globals.h"
#include "astra/AstraObjectManager.h"
#include "astra/Float32ProjectionData2D.h"
#include "astra/Float32VolumeData2D.h"
#include "astra/Float32ProjectionData3D.h"
#include "astra/Float32ProjectionData3DMemory.h"
#include "astra/Float32VolumeData3D.h"
#include "astra/Float32VolumeData3DMemory.h"
#include "astra/ParallelProjectionGeometry3D.h"
#include "astra/ParallelVecProjectionGeometry3D.h"
#include "astra/ConeProjectionGeometry3D.h"
#include "astra/ConeVecProjectionGeometry3D.h"
using namespace std;
using namespace astra;
//-----------------------------------------------------------------------------------------
/**
* id = astra_mex_io_data('create', datatype, geometry, data);
* datatype: ['-vol','-sino']
*/
void astra_mex_data3d_create(int& nlhs, mxArray* plhs[], int& nrhs, const mxArray* prhs[])
{
// step1: get datatype
if (nrhs < 3) {
mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
return;
}
const mxArray * const geometry = prhs[2];
const mxArray * const data = nrhs > 3 ? prhs[3] : NULL;
if (!checkStructs(geometry)) {
mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
return;
}
if (data && !checkDataType(data)) {
mexErrMsgTxt("Data must be single, double or logical.");
return;
}
const string sDataType = mexToString(prhs[1]);
// step2: Allocate data
CFloat32Data3DMemory* pDataObject3D =
allocateDataObject(sDataType, geometry, data);
if (!pDataObject3D) {
// Error message was already set by the function
return;
}
// step3: Initialize data
if (!data) {
mxArray * emptyArray = mxCreateDoubleMatrix(0, 0, mxREAL);
copyMexToCFloat32Array(emptyArray, pDataObject3D->getData(),
pDataObject3D->getSize());
mxDestroyArray(emptyArray);
} else {
copyMexToCFloat32Array(data, pDataObject3D->getData(),
pDataObject3D->getSize());
}
// step4: store data object
int iIndex = CData3DManager::getSingleton().store(pDataObject3D);
// step5: return data id
if (1 <= nlhs) {
plhs[0] = mxCreateDoubleScalar(iIndex);
}
}
//-----------------------------------------------------------------------------------------
/** id = astra_mex_data3d('link', datatype, geometry, data);
*
* Create a new data 3d object in the astra-library.
* type:
* geom: MATLAB struct with the geometry for the data
* data: A MATLAB matrix containing the data.
* This matrix will be edited _in-place_!
* id: identifier of the 3d data object as it is now stored in the astra-library.
*/
#ifdef USE_MATLAB_UNDOCUMENTED
void astra_mex_data3d_link(int& nlhs, mxArray* plhs[], int& nrhs, const mxArray* prhs[])
{
// TODO: Allow empty argument to let this function create its own mxArray
// step1: get datatype
if (nrhs < 4) {
mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
return;
}
const mxArray * const geometry = prhs[2];
const mxArray * const data = nrhs > 3 ? prhs[3] : NULL;
const mxArray * const unshare = nrhs > 4 ? prhs[4] : NULL;
const mxArray * const zIndex = nrhs > 5 ? prhs[5] : NULL;
if (!checkStructs(geometry)) {
mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
return;
}
if (data && !mxIsSingle(data)) {
mexErrMsgTxt("Data must be single.");
return;
}
string sDataType = mexToString(prhs[1]);
// step2: Allocate data
CFloat32Data3DMemory* pDataObject3D =
allocateDataObject(sDataType, geometry, data, unshare, zIndex);
if (!pDataObject3D) {
// Error message was already set by the function
return;
}
// step4: store data object
int iIndex = CData3DManager::getSingleton().store(pDataObject3D);
// step5: return data id
if (1 <= nlhs) {
plhs[0] = mxCreateDoubleScalar(iIndex);
}
}
#endif
//-----------------------------------------------------------------------------------------
/**
* data = astra_mex_data3d('get', id);
*
* Fetch data from the astra-library to a MATLAB matrix.
* id: identifier of the 3d data object as stored in the astra-library.
* data: MATLAB data
*/
void astra_mex_data3d_get(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
generic_astra_mex_data3d_get(nlhs, plhs, nrhs, prhs);
}
//-----------------------------------------------------------------------------------------
/**
* data = astra_mex_data3d('get_single', id);
*
* Fetch data from the astra-library to a MATLAB matrix.
* id: identifier of the 3d data object as stored in the astra-library.
* data: MATLAB data
*/
void astra_mex_data3d_get_single(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
generic_astra_mex_data3d_get(nlhs, plhs, nrhs, prhs);
}
//-----------------------------------------------------------------------------------------
/**
* astra_mex_data3d('store', id, data);
*
* Store MATLAB matrix data in the astra-library.
* id: identifier of the 3d data object as stored in the astra-library.
* data: MATLAB data
*/
void astra_mex_data3d_store(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
// step1: input
if (nrhs < 3) {
mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
return;
}
if (!checkDataType(prhs[2])) {
mexErrMsgTxt("Data must be single or double.");
return;
}
// step2: get data object
CFloat32Data3DMemory* pDataObject = NULL;
if (!checkID(mxGetScalar(prhs[1]), pDataObject)) {
mexErrMsgTxt("Data object not found or not initialized properly.\n");
return;
}
copyMexToCFloat32Array(prhs[2], pDataObject->getData(), pDataObject->getSize());
}
void astra_mex_data3d_dimensions(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
// step1: get input
if (nrhs < 2) {
mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
return;
}
int iDid = (int)(mxGetScalar(prhs[1]));
// step2: get data object
CFloat32Data3D* pData;
if (!(pData = CData3DManager::getSingleton().get(iDid))) {
mexErrMsgTxt("DataObject not valid. \n");
return;
}
// step3: output
if (1 <= nlhs) {
plhs[0] = mxCreateDoubleScalar(pData->getWidth());
}
if (2 <= nlhs) {
plhs[1] = mxCreateDoubleScalar(pData->getHeight());
}
if (3 <= nlhs) {
plhs[2] = mxCreateDoubleScalar(pData->getDepth());
}
}
//-----------------------------------------------------------------------------------------
/** geom = astra_mex_data3d('get_geometry', id);
*
* Fetch the geometry of a 3d data object stored in the astra-library.
* id: identifier of the 3d data object as stored in the astra-library.
* geom: MATLAB-struct containing information about the used geometry.
*/
void astra_mex_data3d_get_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
// parse input
if (nrhs < 2) {
mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
return;
}
if (!mxIsDouble(prhs[1])) {
mexErrMsgTxt("Identifier should be a scalar value. \n");
return;
}
int iDataID = (int)(mxGetScalar(prhs[1]));
// fetch data object
CFloat32Data3D* pDataObject = astra::CData3DManager::getSingleton().get(iDataID);
if (!pDataObject || !pDataObject->isInitialized()) {
mexErrMsgTxt("Data object not found or not initialized properly.\n");
return;
}
// create output
if (1 <= nlhs) {
if (pDataObject->getType() == CFloat32Data3D::PROJECTION) {
CFloat32ProjectionData3DMemory* pDataObject2 = dynamic_cast(pDataObject);
plhs[0] = configToStruct(pDataObject2->getGeometry()->getConfiguration());
}
else if (pDataObject->getType() == CFloat32Data3D::VOLUME) {
CFloat32VolumeData3DMemory* pDataObject2 = dynamic_cast(pDataObject);
plhs[0] = configToStruct(pDataObject2->getGeometry()->getConfiguration());
}
}
}
//-----------------------------------------------------------------------------------------
/** astra_mex_data3d('change_geometry', id, geom);
*
* Change the geometry of a 3d data object.
* id: identifier of the 3d data object as stored in the astra-library.
* geom: the new geometry struct, as created by astra_create_vol/proj_geom
*/
void astra_mex_data3d_change_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
// parse input
if (nrhs < 3) {
mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
return;
}
// get data object
CFloat32Data3DMemory* pDataObject = NULL;
if (!checkID(mxGetScalar(prhs[1]), pDataObject)) {
mexErrMsgTxt("Data object not found or not initialized properly.\n");
return;
}
const mxArray * const geometry = prhs[2];
if (!checkStructs(geometry)) {
mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
return;
}
CFloat32ProjectionData3D* pProjData = dynamic_cast(pDataObject);
if (pProjData) {
// Projection data
// Read geometry
astra::Config* cfg = structToConfig("ProjectionGeometry3D", geometry);
// FIXME: Change how the base class is created. (This is duplicated
// in Projector3D.cpp.)
std::string type = cfg->self.getAttribute("type");
astra::CProjectionGeometry3D* pGeometry = 0;
if (type == "parallel3d") {
pGeometry = new astra::CParallelProjectionGeometry3D();
} else if (type == "parallel3d_vec") {
pGeometry = new astra::CParallelVecProjectionGeometry3D();
} else if (type == "cone") {
pGeometry = new astra::CConeProjectionGeometry3D();
} else if (type == "cone_vec") {
pGeometry = new astra::CConeVecProjectionGeometry3D();
} else {
mexErrMsgTxt("Invalid geometry type.\n");
return;
}
if (!pGeometry->initialize(*cfg)) {
mexErrMsgTxt("Geometry class not initialized. \n");
delete pGeometry;
delete cfg;
return;
}
delete cfg;
// Check dimensions
if (pGeometry->getDetectorColCount() != pProjData->getDetectorColCount() ||
pGeometry->getProjectionCount() != pProjData->getAngleCount() ||
pGeometry->getDetectorRowCount() != pProjData->getDetectorRowCount())
{
mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
delete pGeometry;
return;
}
// If ok, change geometry
pProjData->changeGeometry(pGeometry);
delete pGeometry;
} else {
// Volume data
CFloat32VolumeData3D* pVolData = dynamic_cast(pDataObject);
assert(pVolData);
// Read geometry
astra::Config* cfg = structToConfig("VolumeGeometry3D", geometry);
astra::CVolumeGeometry3D* pGeometry = new astra::CVolumeGeometry3D();
if (!pGeometry->initialize(*cfg))
{
mexErrMsgTxt("Geometry class not initialized. \n");
delete pGeometry;
delete cfg;
return;
}
delete cfg;
// Check dimensions
if (pGeometry->getGridColCount() != pVolData->getColCount() ||
pGeometry->getGridRowCount() != pVolData->getRowCount() ||
pGeometry->getGridSliceCount() != pVolData->getSliceCount())
{
mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
delete pGeometry;
return;
}
// If ok, change geometry
pVolData->changeGeometry(pGeometry);
delete pGeometry;
}
}
//-----------------------------------------------------------------------------------------
/**
* astra_mex_data3d('delete', did1, did2, ...);
*/
void astra_mex_data3d_delete(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
// step1: read input
if (nrhs < 2) {
mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
return;
}
for (int i = 1; i < nrhs; i++) {
int iDataID = (int)(mxGetScalar(prhs[i]));
CData3DManager::getSingleton().remove(iDataID);
}
}
//-----------------------------------------------------------------------------------------
/**
* astra_mex_data3d('clear');
*/
void astra_mex_data3d_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
CData3DManager::getSingleton().clear();
}
//-----------------------------------------------------------------------------------------
/**
* astra_mex_data3d('info');
*/
void astra_mex_data3d_info(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
mexPrintf("%s", astra::CData3DManager::getSingleton().info().c_str());
}
//-----------------------------------------------------------------------------------------
static void printHelp()
{
mexPrintf("Please specify a mode of operation.\n");
mexPrintf("Valid modes: create, get, get_single, delete, clear, info\n");
mexPrintf(" dimensions, get_geometry, change_geometry\n");
}
//-----------------------------------------------------------------------------------------
/**
* ... = astra_mex_io_data(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;
}
initASTRAMex();
// 3D data
if (sMode == std::string("create")) {
astra_mex_data3d_create(nlhs, plhs, nrhs, prhs);
#ifdef USE_MATLAB_UNDOCUMENTED
} else if (sMode == "link") {
astra_mex_data3d_link(nlhs, plhs, nrhs, prhs);
#endif
} else if (sMode == std::string("get")) {
astra_mex_data3d_get(nlhs, plhs, nrhs, prhs);
} else if (sMode == std::string("get_single")) {
astra_mex_data3d_get_single(nlhs, plhs, nrhs, prhs);
} else if (sMode == std::string("store") ||
sMode == std::string("set")) {
astra_mex_data3d_store(nlhs, plhs, nrhs, prhs);
} else if (sMode == std::string("delete")) {
astra_mex_data3d_delete(nlhs, plhs, nrhs, prhs);
} else if (sMode == "clear") {
astra_mex_data3d_clear(nlhs, plhs, nrhs, prhs);
} else if (sMode == "info") {
astra_mex_data3d_info(nlhs, plhs, nrhs, prhs);
} else if (sMode == std::string("dimensions")) {
astra_mex_data3d_dimensions(nlhs, plhs, nrhs, prhs);
} else if (sMode == std::string("get_geometry")) {
astra_mex_data3d_get_geometry(nlhs, plhs, nrhs, prhs);
} else if (sMode == std::string("change_geometry")) {
astra_mex_data3d_change_geometry(nlhs, plhs, nrhs, prhs);
} else {
printHelp();
}
return;
}