-
Notifications
You must be signed in to change notification settings - Fork 101
Create your own algorithm in FAST
This page is a tutorial on how to create your own algorithm in FAST.
The algorithm we will create in this tutorial is very simple. It will double the value of every pixel/voxel in an image and thus we call it DoubleFilter.
First off, we have to define the DoubleFilter class. All algorithms have to extend the ProcessObject class and implement a method called execute. This method is used to execute the algorithm and is called when the pipeline is updated. See the framework design page for details on how the execution pipeline works.
In a file called DoubleFilter.hpp, write the following:
#ifndef DOUBLEFILTER_HPP
#define DOUBLEFILTER_HPP
#include "FAST/ProcessObject.hpp"
namespace fast {
/**
* This is an example filter which doubles the value of each element in an image
*/
class DoubleFilter : public ProcessObject {
FAST_OBJECT(DoubleFilter)
private:
// Constructor
DoubleFilter();
// This method will execute the algorithm
void execute();
};
}; // namespace fast
#endif // DOUBLEFILTER_HPP
And here is the implementation of the class (DoubleFilter.cpp):
#include "DoubleFilter.hpp"
#include "FAST/Data/Image.hpp"
namespace fast {
DoubleFilter::DoubleFilter() {
// This creates an input port of type Image.
createInputPort<Image>(0);
// This creates an output port of type Image.
// The OUTPUT_DEPENDS_ON_INPUT flag means that if the input
// is a static image, the output will also be a static image,
// and if the input is a dynamic image, the output will also
// be a dynamic image.
createOutputPort<Image>(0, OUTPUT_DEPENDS_ON_INPUT, 0);
// This creates an OpenCL program from a source file on disk
createOpenCLProgram(std::string(FAST_SOURCE_DIR) + "Tests/Algorithms/DoubleFilter.cl");
}
/*
* This function performs the filter serially on the Host using plain old C++.
* It is templated so that it can support images of different data types.
*/
template<class T>
inline void executeAlgorithmOnHost(Image::pointer input, Image::pointer output) {
ImageAccess::pointer inputAccess = input->getImageAccess(ACCESS_READ);
ImageAccess::pointer outputAccess = output->getImageAccess(ACCESS_READ_WRITE);
T * inputData = (T*)inputAccess->get();
T * outputData = (T*)outputAccess->get();
unsigned int nrOfElements = input->getWidth()*input->getHeight()*input->getDepth()*input->getNrOfComponents();
for(unsigned int i = 0; i < nrOfElements; i++) {
outputData[i] = 2.0*inputData[i];
}
}
void DoubleFilter::execute() {
// Get input and output data
Image::pointer input = getStaticInputData<Image>();
Image::pointer output = getStaticOutputData<Image>();
// Initialize output image
output->createFromImage(input);
if(getMainDevice()->isHost()) {
// Execution device is Host, use the executeAlgorithmOnHost function with the given data type
switch(input->getDataType()) {
// This macro creates a case statement for each data type and sets FAST_TYPE to the correct C++ data type
fastSwitchTypeMacro(executeAlgorithmOnHost<FAST_TYPE>(input, output));
}
} else {
// Execution device is an OpenCL device
OpenCLDevice::pointer device = getMainDevice();
// Set build options based on the data type of the data
std::string buildOptions = "-DTYPE=" + getCTypeAsString(input->getDataType());
// Compile the code
cl::Kernel kernel = cl::Kernel(getOpenCLProgram(device, "", buildOptions), "doubleFilter");
// Get global size for the kernel
cl::NDRange globalSize(input->getWidth()*input->getHeight()*input->getDepth()*input->getNrOfComponents());
// Set the arguments for the kernel
OpenCLBufferAccess::pointer inputAccess = input->getOpenCLBufferAccess(ACCESS_READ, device);
OpenCLBufferAccess::pointer outputAccess = output->getOpenCLBufferAccess(ACCESS_READ_WRITE, device);
kernel.setArg(0, *inputAccess->get());
kernel.setArg(1, *outputAccess->get());
// Execute the kernel
device->getCommandQueue().enqueueNDRangeKernel(
kernel,
cl::NullRange,
globalSize,
cl::NullRange
);
}
}
} // end namespace fast
And the OpenCL kernel code (DoubleFilter.cl):
__kernel void doubleFilter(
__global TYPE * input,
__global TYPE * output
) {
output[get_global_id(0)] = input[get_global_id(0)]*2;
}
// Import an image
ImageFileImporter::pointer importer = ImageFileImporter::New();
importer->setFilename("someimage.png");
// Run the filter
DoubleFilter::pointer filter = DoubleFilter::New();
filter->setInputConnection(importer->getOutputPort());
// Render image
ImageRenderer::pointer renderer = ImageRenderer::New();
renderer->addInputConnection(filter->getOutputPort());
// Create window and start pipeline
SimpleWindow::pointer window = SimpleWindow::New();
window->addRenderer(renderer);
window->start();
If this wiki page lacks some information or is incorrect please let us know! You can edit this wiki page yourself, send an email to [email protected] or