2011-10-29 34 views
0

我正在学习数字图像处理,如果有人能评论polymorphism是否适用于这种情况,或者是否有更好的类设计,我将非常感激。案例研究:图像处理的多态性

基本上,2D滤镜/内核可以是:non-separableseparable。一个重要的内核操作是convolution以及计算它的方式取决于过滤器类型。

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; 
}; 

注意,即使是CSeparableKernel2D类可以有两个私有成员:CKernel1D<T> m_X, m_Y。类别可以有其自己的myConvolution方法,即myConvolutionRows,myConvolutionCols。另外,通常,我们希望对给定图像应用一组filters(可分离/不可分离),即将输入图像与给定的filter进行卷积。因此,根据filter type,应该调用相应的myConvolution方法。

(1)哪一种应该是最干净的方式能够做到的事情。喜欢?

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); // Would like to assign a non-sep filter. 
m_vFilterbank.push_back(mySepFilter1); // Would like to assign a sep filter. 

在我看来,唯一的方法就是使用多态性,对吗?

CKernel2D<float> * pKernel2d = NULL; 
pKernel2d = &mySepFilter1; m_vFilterbank.push_back(*pKernel2d); 
pKernel2d = &myNonSepFilter1; m_vFilterbank.push_back(*pKernel2d); 

(2)现在假设我们filterbank已经挤满了类型的内核,应用的输入图像的卷积,这将是足以做到:

outputSeparable1 = m_vFilterbank.at(0).myConvolution(input); 
outputNonSeparable1 = m_vFilterbank.at(1).myConvolution(input); 

(3)现在想象一下,我想有以下原型朋友convolution功能:

friend CMatrix<T> convolution(const CKernel2D<T> &, const CImage<T> &); 

再次,我想的是正确的myConvolution甲基od的调用取决于kernel类型。我怎么能实现这样的操作?我读了某事。关于Virtual Friend Function Idiom,你认为在这种情况下应用这个习语是否合理?

所有评论&建议真的很受欢迎;-)我真的很想听听你对这个设计有什么看法?有没有更好的方法来设计这些功能?

回答

0

由于图像分析需要大量的计算能力,所以良好的性能是重要的。大家都知道多态是一件好事,但它当然会增加一个运行时抽象层,所以它比静态链接的代码慢。

由于您已经在使用模板,为什么不使用使用模板的编译时抽象层?像STL一样,你可以将你的算法封装在类中,并通过模板参数传递它们。

我在这里发布一个简单的例子来显示原理。

template <typename T, typename FUNCTOR> 
class ArrayTransformer 
{ 
public: 

    static void Transform(T* array, int count) 
    { 
     for (int i = 0; i < count; ++i) 
      FUNCTOR::Transform(array[i]); 
    } 

    template <int N> 
    static void Transform(T (&array)[N]) 
    { 
     for (int i = 0; i < N; ++i) 
      FUNCTOR::Transform(array[i]); 
    } 
}; 

template <typename T> 
class NegateTransformer 
{ 
public: 

    static void Transform(T& value) 
    { 
     value = -value; 
    } 
}; 

int main() 
{ 
    int array[] = { 1, 2, 3, 4, 5, 6 }; 
    ArrayTransformer<int, NegateTransformer<int> >::Transform(array); 
    .... 
    return 0; 
} 

新一代的编译器可以优化这段代码相当不错:)的开销,如果您使用的是编译好的,你在释放模式编译,将是零。

当然,如果你必须调用内函子的几千次,如果你只需要使用多态就可以调用它,这是有意义的。 您也可以将两种技术混合使用,以获得内循环中的高性能,同时在更高级别实现易用性。

+0

感谢您的帖子。我从来没有使用静态链接的代码,现在看看。而且,就我而言,像'NegateTransformer'这样的类可以对应一个特定的'kernel type',对吧? 'Transform'方法就是'卷积'和'ArrayTransformer',它可以看到整个图片,然后是'Kernel2D ',对吧? – Tin

+0

@Mark,这个多态函数每个'kernel convolution'只调用一次。在'implementation'中,我有一些嵌套循环来处理像素。 – Tin