【问题标题】:Case Study: Polymorphism for Image Processing案例研究:图像处理的多态性
【发布时间】:2011-10-29 14:31:54
【问题描述】:

我正在自学数字图像处理,如果有人能评论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&lt;T&gt; m_X, m_YCKernel1D&lt;T&gt; 类可以有自己的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.

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

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> &);

再次,我希望根据 kernel 类型调用正确的 myConvolution 方法。我怎么能实现这样的操作?我读了某事。关于Virtual Friend Function Idiom,您认为在这种情况下应用该成语是否有意义?

非常欢迎所有 cmets 和建议 ;-) 我真的很想听听您对这个设计的看法?有没有更好的方法来设计这些功能?

【问题讨论】:

    标签: c++ templates polymorphism virtual friend


    【解决方案1】:

    由于图像分析需要大量计算能力,因此良好的性能很重要。 每个人都知道多态是个好东西,但它当然增加了运行时抽象层,所以它比静态链接代码慢。

    既然您已经在使用模板,为什么不使用模板来使用编译时抽象层呢?与 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;
    }
    

    新一代编译器可以很好地优化这段代码:) 如果你使用一个好的编译器并且你在发布模式下编译,那么开销将是零。

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

    【讨论】:

    • 感谢您的帖子。我从来没有使用过静态链接的代码,现在看看。此外,就我而言,NegateTransformer 之类的类将对应于例如特定的kernel type,对吧? Transform 方法将是 convolution 和看到全貌的 ArrayTransformer 将是 Kernel2D&lt;T&gt;,对吧?
    • @Mark,每个kernel convolution 只调用一次多态函数。在implementation 中,我有一些嵌套循环来处理像素。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-25
    • 2012-01-23
    • 2021-07-04
    • 1970-01-01
    • 2020-11-08
    • 2020-10-25
    相关资源
    最近更新 更多