/*
-----------------------------------------------------------------------
Copyright 2012 iMinds-Vision Lab, University of Antwerp
Contact: astra@ua.ac.be
Website: http://astra.ua.ac.be
This file is part of the
All Scale Tomographic Reconstruction Antwerp Toolbox ("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 .
-----------------------------------------------------------------------
$Id$
*/
#include
#include "algo.h"
#include "par_fp.h"
#include "fan_fp.h"
#include "par_bp.h"
#include "fan_bp.h"
#include "util.h"
#include "arith.h"
namespace astraCUDA {
ReconAlgo::ReconAlgo()
{
angles = 0;
TOffsets = 0;
fanProjs = 0;
shouldAbort = false;
useVolumeMask = false;
useSinogramMask = false;
D_maskData = 0;
D_smaskData = 0;
D_sinoData = 0;
D_volumeData = 0;
useMinConstraint = false;
useMaxConstraint = false;
freeGPUMemory = false;
}
ReconAlgo::~ReconAlgo()
{
reset();
}
void ReconAlgo::reset()
{
delete[] angles;
delete[] TOffsets;
delete[] fanProjs;
if (freeGPUMemory) {
cudaFree(D_maskData);
cudaFree(D_smaskData);
cudaFree(D_sinoData);
cudaFree(D_volumeData);
}
angles = 0;
TOffsets = 0;
fanProjs = 0;
shouldAbort = false;
useVolumeMask = false;
useSinogramMask = false;
D_maskData = 0;
D_smaskData = 0;
D_sinoData = 0;
D_volumeData = 0;
useMinConstraint = false;
useMaxConstraint = false;
freeGPUMemory = false;
}
bool ReconAlgo::setGPUIndex(int iGPUIndex)
{
if (iGPUIndex != -1) {
cudaSetDevice(iGPUIndex);
cudaError_t err = cudaGetLastError();
// Ignore errors caused by calling cudaSetDevice multiple times
if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
return false;
}
return true;
}
bool ReconAlgo::enableVolumeMask()
{
useVolumeMask = true;
return true;
}
bool ReconAlgo::enableSinogramMask()
{
useSinogramMask = true;
return true;
}
bool ReconAlgo::setGeometry(const SDimensions& _dims, const float* _angles)
{
dims = _dims;
angles = new float[dims.iProjAngles];
memcpy(angles, _angles, sizeof(angles[0]) * dims.iProjAngles);
delete[] fanProjs;
fanProjs = 0;
return true;
}
bool ReconAlgo::setFanGeometry(const SDimensions& _dims,
const SFanProjection* _projs)
{
dims = _dims;
fanProjs = new SFanProjection[dims.iProjAngles];
memcpy(fanProjs, _projs, sizeof(fanProjs[0]) * dims.iProjAngles);
delete[] angles;
angles = 0;
return true;
}
bool ReconAlgo::setTOffsets(const float* _TOffsets)
{
// TODO: determine if they're all zero?
TOffsets = new float[dims.iProjAngles];
memcpy(TOffsets, _TOffsets, sizeof(angles[0]) * dims.iProjAngles);
return true;
}
bool ReconAlgo::setVolumeMask(float* _D_maskData, unsigned int _maskPitch)
{
assert(useVolumeMask);
D_maskData = _D_maskData;
maskPitch = _maskPitch;
return true;
}
bool ReconAlgo::setSinogramMask(float* _D_smaskData, unsigned int _smaskPitch)
{
assert(useSinogramMask);
D_smaskData = _D_smaskData;
smaskPitch = _smaskPitch;
return true;
}
bool ReconAlgo::setBuffers(float* _D_volumeData, unsigned int _volumePitch,
float* _D_projData, unsigned int _projPitch)
{
D_volumeData = _D_volumeData;
volumePitch = _volumePitch;
D_sinoData = _D_projData;
sinoPitch = _projPitch;
return true;
}
bool ReconAlgo::setMinConstraint(float fMin)
{
fMinConstraint = fMin;
useMinConstraint = true;
return true;
}
bool ReconAlgo::setMaxConstraint(float fMax)
{
fMaxConstraint = fMax;
useMaxConstraint = true;
return true;
}
bool ReconAlgo::allocateBuffers()
{
bool ok;
ok = allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
if (!ok)
return false;
ok = allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch);
if (!ok) {
cudaFree(D_volumeData);
D_volumeData = 0;
return false;
}
if (useVolumeMask) {
ok = allocateVolume(D_maskData, dims.iVolWidth+2, dims.iVolHeight+2, maskPitch);
if (!ok) {
cudaFree(D_volumeData);
cudaFree(D_sinoData);
D_volumeData = 0;
D_sinoData = 0;
return false;
}
}
if (useSinogramMask) {
ok = allocateVolume(D_smaskData, dims.iProjDets+2, dims.iProjAngles, smaskPitch);
if (!ok) {
cudaFree(D_volumeData);
cudaFree(D_sinoData);
cudaFree(D_maskData);
D_volumeData = 0;
D_sinoData = 0;
D_maskData = 0;
return false;
}
}
freeGPUMemory = true;
return true;
}
bool ReconAlgo::copyDataToGPU(const float* pfSinogram, unsigned int iSinogramPitch, float fSinogramScale,
const float* pfReconstruction, unsigned int iReconstructionPitch,
const float* pfVolMask, unsigned int iVolMaskPitch,
const float* pfSinoMask, unsigned int iSinoMaskPitch)
{
if (!pfSinogram)
return false;
if (!pfReconstruction)
return false;
bool ok = copySinogramToDevice(pfSinogram, iSinogramPitch,
dims.iProjDets,
dims.iProjAngles,
D_sinoData, sinoPitch);
if (!ok)
return false;
// rescale sinogram to adjust for pixel size
processVol(D_sinoData, fSinogramScale,
//1.0f/(fPixelSize*fPixelSize),
sinoPitch,
dims.iProjDets, dims.iProjAngles);
ok = copyVolumeToDevice(pfReconstruction, iReconstructionPitch,
dims.iVolWidth, dims.iVolHeight,
D_volumeData, volumePitch);
if (!ok)
return false;
if (useVolumeMask) {
if (!pfVolMask)
return false;
ok = copyVolumeToDevice(pfVolMask, iVolMaskPitch,
dims.iVolWidth, dims.iVolHeight,
D_maskData, maskPitch);
if (!ok)
return false;
}
if (useSinogramMask) {
if (!pfSinoMask)
return false;
ok = copySinogramToDevice(pfSinoMask, iSinoMaskPitch,
dims.iProjDets, dims.iProjAngles,
D_smaskData, smaskPitch);
if (!ok)
return false;
}
return true;
}
bool ReconAlgo::getReconstruction(float* pfReconstruction,
unsigned int iReconstructionPitch) const
{
bool ok = copyVolumeFromDevice(pfReconstruction, iReconstructionPitch,
dims.iVolWidth,
dims.iVolHeight,
D_volumeData, volumePitch);
if (!ok)
return false;
return true;
}
bool ReconAlgo::callFP(float* D_volumeData, unsigned int volumePitch,
float* D_projData, unsigned int projPitch,
float outputScale)
{
if (angles) {
assert(!fanProjs);
return FP(D_volumeData, volumePitch, D_projData, projPitch,
dims, angles, TOffsets, outputScale);
} else {
assert(fanProjs);
return FanFP(D_volumeData, volumePitch, D_projData, projPitch,
dims, fanProjs, outputScale);
}
}
bool ReconAlgo::callBP(float* D_volumeData, unsigned int volumePitch,
float* D_projData, unsigned int projPitch)
{
if (angles) {
assert(!fanProjs);
return BP(D_volumeData, volumePitch, D_projData, projPitch,
dims, angles, TOffsets);
} else {
assert(fanProjs);
return FanBP(D_volumeData, volumePitch, D_projData, projPitch,
dims, fanProjs);
}
}
}