Skip to content

Commit

Permalink
Merge pull request #5 from smistad/upgrade-fast
Browse files Browse the repository at this point in the history
FX-19: Upgraded fast to latest version and implemented manual seed point
  • Loading branch information
jonei authored May 16, 2017
2 parents d864786 + 2e20435 commit fdbf088
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 31 deletions.
15 changes: 9 additions & 6 deletions install/cx/build/cxComponents.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,14 +526,12 @@ def help(self):
# def path(self):
# return self.controlData.getWorkingPath() + "/FAST"
def sourcePath(self):
return self.controlData.getWorkingPath() + "/FAST/FAST/source"
return self.controlData.getWorkingPath() + "/FAST/FAST/"
def repository(self):
#return 'git@github.com:smistad/FAST'
return 'git@github.com:jbake/FAST'
return 'git@github.com:smistad/FAST'
def update(self):
self._getBuilder().gitSetRemoteURL(self.repository())
self._getBuilder().gitCheckout('75627f9c63891584d9a8028568294f4c831a87df')
# self._getBuilder().gitCheckoutBranch('set_kernel_root_dir')
self._getBuilder().gitCheckout('c2522765d3bb369142ad53dd20dfb6d54c8e95ac')
# branch = 'set_kernel_root_dir'
# self._getBuilder()._changeDirToSource()
# runShell('git checkout %s' % branch, ignoreFailure=False)
Expand All @@ -544,9 +542,14 @@ def configure(self):
add = builder.addCMakeOption
append = builder.appendCMakeOption
add('FAST_MODULE_OpenIGTLink:BOOL', False)
add('FAST_MODULE_Visualization:BOOL', False)
add('FAST_MODULE_Python:BOOL', False)
add('FAST_MODULE_NeuralNetwork:BOOL', False)
add('FAST_MODULE_VTK:BOOL', True)
add('FAST_DOWNLOAD_TEST_DATA:BOOL', False)
add('FAST_BUILD_EXAMPLES:BOOL', False)
add('FAST_BUILD_TOOLS:BOOL', False)
add('FAST_BUILD_TESTS:BOOL', False)
add('FAST_VTK_INTEROP:BOOL', True)
add('VTK_DIR:PATH', self._createSibling(VTK).configPath())
add('EIGEN3_INCLUDE_DIR:PATH', '%s' % self._createSibling(Eigen).sourcePath())
if(platform.system() == 'Windows'):
Expand Down
16 changes: 6 additions & 10 deletions source/plugins/org.custusx.filter.airways/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
project(org_custusx_filter_airways)

add_definitions(-DBOOST_SYSTEM_NO_DEPRECATED)

include(cxInstallUtilities)

macro(cx_initialize_FAST)
find_package( FAST REQUIRED)
include(${FAST_USE_FILE})
find_package(FAST REQUIRED)
include_directories("${FAST_DIR}/../FAST/source/")
link_directories("${FAST_DIR}/lib/")
add_definitions("-DFAST_SOURCE_DIR=\"${FAST_DIR}/../FAST/source/FAST/\"")
message("===========================")
message("Initializing FAST in Airways plugin")
message("-- ${FAST_LIBRARY_DIRS}")
message("-- ${FAST_DIR}/../FAST/source/")
message("===========================")
cx_install_add_library_dirs(${FAST_LIBRARY_DIRS})
cx_install_add_library_dirs(${FAST_DIR}/lib/)
endmacro()

find_package(GLEW REQUIRED)
find_package(OpenCL REQUIRED)
cx_initialize_FAST()

#### Enable C++11
Expand Down Expand Up @@ -75,11 +73,9 @@ set(PLUGIN_target_libraries
${PLUGIN_target_libraries}

PRIVATE
OpenCLUtilityLibrary
FAST
Qt5::OpenGL
${OPENCL_LIBRARIES}
${GLEW_LIBRARY}
cxResource
cxResourceFilter
cxResourceVisualization
Expand Down
119 changes: 110 additions & 9 deletions source/plugins/org.custusx.filter.airways/cxAirwaysFilterService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FAST/Algorithms/CenterlineExtraction/CenterlineExtraction.hpp"
#include "FAST/Importers/ImageFileImporter.hpp"
#include "FAST/Exporters/VTKImageExporter.hpp"
#include "FAST/Exporters/VTKLineSetExporter.hpp"
#include "FAST/Exporters/VTKMeshExporter.hpp"
#include "FAST/Data/Segmentation.hpp"
#include "FAST/SceneGraph.hpp"

Expand Down Expand Up @@ -93,13 +93,85 @@ QString AirwaysFilter::getHelp() const
"</html>";
}


Vector3D AirwaysFilter::getSeedPointFromTool(SpaceProviderPtr spaceProvider, DataPtr data)
{
// Retrieve position of tooltip and use it as seed point
Vector3D point = spaceProvider->getActiveToolTipPoint(
spaceProvider->getD(data));

// Have to multiply by the inverse of the spacing to get the voxel position
ImagePtr image = boost::dynamic_pointer_cast<Image>(data);
double spacingX, spacingY, spacingZ;
image->getBaseVtkImageData()->GetSpacing(spacingX, spacingY, spacingZ);
point(0) = point(0) * (1.0 / spacingX);
point(1) = point(1) * (1.0 / spacingY);
point(2) = point(2) * (1.0 / spacingZ);

std::cout << "the selected seed point is: " << point(0) << " " << point(1)
<< " " << point(2) << "\n";

return point;
}

int * getImageSize(DataPtr inputImage)
{
ImagePtr image = boost::dynamic_pointer_cast<Image>(inputImage);
return image->getBaseVtkImageData()->GetDimensions();
}

bool AirwaysFilter::isSeedPointInsideImage(Vector3D seedPoint, DataPtr image)
{
int * size = getImageSize(image);
std::cout << "size of image is: " << size[0] << " " << size[1] << " "
<< size[2] << "\n";
int x = (int) seedPoint(0);
int y = (int) seedPoint(1);
int z = (int) seedPoint(2);
bool result = x >= 0 && y >= 0 && z >= 0 && x < size[0] && y < size[1]
&& z < size[2];
return result;
}

bool AirwaysFilter::preProcess()
{
DataPtr inputImage = mInputTypes[0].get()->getData();
if (!inputImage)
{
CX_LOG_ERROR() << "No input data selected";
return false;
}

if (inputImage->getType() != "image")
{
CX_LOG_ERROR() << "Input data has to be an image";
return false;
}

std::string filename = (patientService()->getActivePatientFolder()
+ "/" + inputImage->getFilename()).toStdString();

// only check seed point inside image if use seed point is checked
bool useManualSeedPoint = getManualSeedPointOption(mOptions)->getValue();
if(useManualSeedPoint)
{
seedPoint = getSeedPointFromTool(mServices->spaceProvider(), inputImage);
if(!isSeedPointInsideImage(seedPoint, inputImage)) {
CX_LOG_ERROR() << "Seed point is not inside image. Use cursor to set seed point inside trachea in the CT image.";
return false;
}
}
mInputImage = patientService()->getData<Image>(inputImage->getUid());

return true;
}

bool AirwaysFilter::execute()
{
CX_LOG_INFO() << "EXECUTING AIRWAYS FILTER";
ImagePtr input = this->getCopiedInputImage();
if (!input)
// Check if pre process went ok:
if(!mInputImage)
return false;
mInputImage = input;

QString q_filename = "";
QString activePatienFolder = patientService()->getActivePatientFolder();
Expand All @@ -111,10 +183,10 @@ bool AirwaysFilter::execute()

std::string filename = q_filename.toStdString();
try {
QString kernelDir = cx::DataLocations::findConfigFolder("/FAST", FAST_SOURCE_DIR);
fast::DeviceManager::getInstance().setKernelRootPath(kernelDir.toStdString());
fast::Config::getTestDataPath(); // needed for initialization
QString cacheDir = cx::DataLocations::getCachePath();
fast::DeviceManager::getInstance().setWritableCachePath(cacheDir.toStdString());
fast::Config::setKernelBinaryPath(cacheDir.toStdString());
fast::Config::setKernelSourcePath(std::string(FAST_SOURCE_DIR));

// Import image data from disk
fast::ImageFileImporter::pointer importer = fast::ImageFileImporter::New();
Expand All @@ -126,7 +198,22 @@ bool AirwaysFilter::execute()

// Do segmentation
fast::AirwaySegmentation::pointer segmentation = fast::AirwaySegmentation::New();
bool useManualSeedPoint = getManualSeedPointOption(mOptions)->getValue();
if(useManualSeedPoint)
{
CX_LOG_INFO() << "Using seed point: " << seedPoint.transpose();
segmentation->setSeedPoint(seedPoint(0), seedPoint(1), seedPoint(2));
}
segmentation->setInputConnection(importer->getOutputPort());
try {
segmentation->update();
} catch(fast::Exception &e) {

CX_LOG_ERROR() << "The airways filter failed.";
if(!useManualSeedPoint)
CX_LOG_ERROR() << "Try to set the seed point manually.";
return false;
}

// Convert fast segmentation data to VTK data which CX can use
vtkSmartPointer<fast::VTKImageExporter> vtkExporter = fast::VTKImageExporter::New();
Expand All @@ -147,7 +234,7 @@ bool AirwaysFilter::execute()
centerline->setInputConnection(segmentation->getOutputPort());

// Get centerline
vtkSmartPointer<fast::VTKLineSetExporter> vtkCenterlineExporter = fast::VTKLineSetExporter::New();
vtkSmartPointer<fast::VTKMeshExporter> vtkCenterlineExporter = fast::VTKMeshExporter::New();
vtkCenterlineExporter->setInputConnection(centerline->getOutputPort());
mCenterlineOutput = vtkCenterlineExporter->GetOutput();
vtkCenterlineExporter->Update();
Expand Down Expand Up @@ -205,7 +292,6 @@ bool AirwaysFilter::postProcess()
// Set output
mOutputTypes[1]->setValue(contour->getUid());

// TODO get centerline somehow
QString uid = mInputImage->getUid() + "_centerline%1";
QString name = mInputImage->getName() + " centerline%1";
MeshPtr centerline = patientService()->createSpecificData<Mesh>(uid, name);
Expand All @@ -220,6 +306,7 @@ bool AirwaysFilter::postProcess()

void AirwaysFilter::createOptions()
{
mOptionsAdapters.push_back(this->getManualSeedPointOption(mOptions));
}

void AirwaysFilter::createInputTypes()
Expand Down Expand Up @@ -251,5 +338,19 @@ void AirwaysFilter::createOutputTypes()
}


BoolPropertyPtr AirwaysFilter::getManualSeedPointOption(QDomElement root)
{
BoolPropertyPtr retval =
BoolProperty::initialize("Use manual seed point",
"",
"If the automatic seed point detection algorithm fails you can use cursor to set the seed point "
"inside trachea of the patient. "
"Then tick this checkbox to use the manual seed point in the airways filter.",
false, root);
return retval;

}


} /* namespace cx */

Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,9 @@ typedef vtkSmartPointer<class vtkPolyData> vtkPolyDataPtr;
namespace cx {

/**
* Filter for segmenting and extract the centerline of a volume.
* Filter for airway segmentation and centerline extraction of a CT volume.
*
* This filter can run either on the gpu or cpu.
*
* Algorithm written by Erik Smistad. For more information, see paper:
* "GPU-Based Airway Segmentation and Centerline Extraction for Image Guided Bronchoscopy."
* Algorithm written by Erik Smistad.
*
*/
class org_custusx_filter_airways_EXPORT AirwaysFilter : public FilterImpl
Expand All @@ -75,6 +72,7 @@ Q_INTERFACES(cx::Filter)
virtual QString getName() const;
virtual QString getHelp() const;

bool preProcess();
virtual bool execute();
virtual bool postProcess();

Expand All @@ -84,11 +82,14 @@ Q_INTERFACES(cx::Filter)
virtual void createOutputTypes();

private:
//DoublePropertyPtr getNoiseLevelOption(QDomElement root);
static Vector3D getSeedPointFromTool(SpaceProviderPtr spaceProvider, DataPtr image);
static bool isSeedPointInsideImage(Vector3D, DataPtr);
BoolPropertyPtr getManualSeedPointOption(QDomElement root);
vtkImageDataPtr mSegmentationOutput;
vtkPolyDataPtr mCenterlineOutput;
Transform3D mTransformation;
ImagePtr mInputImage;
Vector3D seedPoint;

};
typedef boost::shared_ptr<class AirwaysFilter> AirwaysFilterPtr;
Expand Down

0 comments on commit fdbf088

Please sign in to comment.