I study digital image processing on my own and will be very grateful if anyone can comment on whether polymorphism should be applied for this case or if there is a better class design.
Basically, a 2D filter / core can be: non-separable or separable . An important kernel operation is convolution and the way it is calculated depends on the type of filter.
template < typename T > class CKernel2D{ public: //.... virtual CMatrix<T> myConvolution(const CMatrix<T> & input) = 0; //.... }; template < typename T > class CNonSeparableKernel : public CKernel2D<T> { public: //.... CMatrix<T> myConvolution(const CMatrix<T> & input ); void initNonSeparableFilter1( double, int ); //.... private: CMatrix<T> m_Kernel; }; template < typename T > class CSeparableKernel2D : public CKernel2D<T>{ public: //.... CMatrix<T> myConvolution(const CMatrix<T> & input ); void initSeparableFilter1( double, double ); //.... private: std::vector<T> m_KernelX; std::vector<T> m_KernelY; };
Note that even the CSeparableKernel2D class can have two private members: CKernel1D<T> m_X, m_Y . The class CKernel1D<T> may have its own method myConvolution , i.e. myConvolutionRows , myConvolutionCols .
In addition, as a rule, we would like to apply a set of filters (shared / inseparable) to a given image, that is, convolution of the input image with a given filter . Therefore, depending on the filter type should call the corresponding myConvolution method.
(1) What should be the cleanest way to do smth. as?
CNonSeparableKernel<float> myNonSepFilter1; myNonSepFilter1.initNonSeparableFilter1(3.0, 1); CNonSeparableKernel<float> mySepFilter1; mySepFilter1.initSeparableFilter1(0.5, 0.5); std::vector<CKernel2D<float> > m_vFilterbank; m_vFilterbank.push_back(myNonSepFilter1);
It seemed to me that the only way to do this was to use polymorphism, right?
CKernel2D<float> * pKernel2d = NULL; pKernel2d = &mySepFilter1; m_vFilterbank.push_back(*pKernel2d); pKernel2d = &myNonSepFilter1; m_vFilterbank.push_back(*pKernel2d);
(2) Now, assuming that our filterbank already filled with nuclear types of both types, to apply convolution on the input image, this would be enough:
outputSeparable1 = m_vFilterbank.at(0).myConvolution(input); outputNonSeparable1 = m_vFilterbank.at(1).myConvolution(input);
(3) Now imagine that I would like to have a convolution friend function with the following prototype:
friend CMatrix<T> convolution(const CKernel2D<T> &, const CImage<T> &);
again, I would like the correct myConvolution method to be called in kernel . How can I achieve such an operation? I am reading. About Virtual Friend Function Idiom , do you think it would be wise to apply this idiom for such a case?
All comments and suggestions are really welcome ;-) I would really like to hear what you think about this design? Is there a better way to develop these features?