案例研究:图像处理的多态性

时间:2011-10-29 14:31:55

标签: c++ templates polymorphism virtual friend

我正在自己学习数字图像处理,如果有人可以评论是否应该为这种情况应用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_YCKernel1D<T>类可以有自己的myConvolution方法,即myConvolutionRowsmyConvolutionCols

此外,通常,我们希望将一组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.

在我看来,唯一的方法是使用polimorphism,对吗?

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类型调用正确的kernel方法。我怎么能实现这样的操作?我读了......关于Virtual Friend Function Idiom,你认为,将这个成语用于这种情况是否有意义?

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

1 个答案:

答案 0 :(得分: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;
}

新一代编译器可以很好地优化这些代码:)如果您使用的是良好的编译器并且在发布模式下编译,则开销将为零。

当然,如果你必须多次调用内部函子,这是有道理的,如果你只能在只使用多态时调用它。 您还可以混合使用这两种技术,以在内循环中获得高性能,同时在更高级别上轻松实现可用性。