patterncppMinor
Image Processing Pipeline
Viewed 0 times
processingimagepipeline
Problem
I'm currently toying around with some Computer Vision algorithms and always wanted to learn more about templates, so I came up with the idea to build a templated Image Processing Pipeline.
I want the pipeline to be built of several task blocks which I want to plug into each other sequentially. For a specific block, its input and output types are fixed. I ultimately want to be able to inherently control for a block to only accept the next block if the output type of the current is identical to the input type of the next.
Consequently,
This is what I was able to come up with:
Abstract base classes:
Example implementation:
`class Str2IntPipelineTask : public AbstractPipelineTask {
public:
Str2IntPipelineTask( AbstractInput* _nextTask = NULL )
: AbstractPipelineTask( _nextTask ) { }
virtual ~Str2IntPipelineTask() { }
virtual int executeTask( std::string& _input ) {
return atoi( _input.c_str() );
}
};
class Int2IntPipelineTask : public AbstractPipelineTask {
public:
Int
I want the pipeline to be built of several task blocks which I want to plug into each other sequentially. For a specific block, its input and output types are fixed. I ultimately want to be able to inherently control for a block to only accept the next block if the output type of the current is identical to the input type of the next.
Block_N Block_N+1
_______________ _________________
int | | str | | float
--->| str = f1(int) |------>| float = f2(str) |------->
|_______________| |_________________|
Consequently,
Block_N+2 would have to accept float as input and may have an arbitrary output type. This is what I was able to come up with:
Abstract base classes:
template
class AbstractInput {
public:
virtual ~AbstractInput() { }
virtual void call( I _input ) = 0;
};
template
class AbstractPipelineTask : public AbstractInput {
public:
typedef AbstractInput* Ptr;
AbstractPipelineTask( AbstractInput* _nextTask = NULL)
: m_nextTask ( _nextTask ) { }
virtual void call( I _input ) {
m_input = _input;
m_output = executeTask( m_input );
if ( m_nextTask )
m_nextTask->call( m_output );
}
virtual O executeTask( I& _input ) = 0;
protected:
AbstractInput* m_nextTask;
I m_input;
O m_output;
};
Example implementation:
`class Str2IntPipelineTask : public AbstractPipelineTask {
public:
Str2IntPipelineTask( AbstractInput* _nextTask = NULL )
: AbstractPipelineTask( _nextTask ) { }
virtual ~Str2IntPipelineTask() { }
virtual int executeTask( std::string& _input ) {
return atoi( _input.c_str() );
}
};
class Int2IntPipelineTask : public AbstractPipelineTask {
public:
Int
Solution
-
Since none of these
-
Consider making the magic number
-
This is specific to Visual Studio, thus is non-portable:
It should be changed to this to fit the standard:
-
In your various
Since none of these
classes have private members, they can be structs instead. As such, you'll no longer need to explicitly give them public inheritance.-
Consider making the magic number
42.f a constant so that its intent is known.-
This is specific to Visual Studio, thus is non-portable:
int _tmain(int argc, _TCHAR* argv[])It should be changed to this to fit the standard:
int main(int argc, char* argv[])-
In your various
executeTask() functions, I believe you're meaning to pass by const&, not just by reference. You're not modifying the argument, so const is best with them.Code Snippets
int _tmain(int argc, _TCHAR* argv[])int main(int argc, char* argv[])Context
StackExchange Code Review Q#64988, answer score: 3
Revisions (0)
No revisions yet.