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

Case Study: Polymorphism for Image Processing

本文关键字:多态性 图像处理 案例      更新时间:2023-10-16

我正在自学数字图像处理,如果有人能评论一下这个案例是否应该使用polymorphism或者是否有更好的类设计,我将非常感激。

基本上,2D Filter/Kernel可以是: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方法,即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> &);
再次

,我希望根据kernel类型调用适当的myConvolution方法。我怎样才能实现这样的操作?我读了一些关于Virtual Friend Function Idiom的东西,你认为,在这种情况下应用这个成语有意义吗?

所有注释&我真的很想听听你对这个设计的看法。是否有更好的方法来设计这些功能?

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

既然你已经在使用模板,为什么你不使用一个编译时抽象层使用模板?像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;
}

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

当然,这是有意义的,如果你需要调用内部函子上千次,如果你只需要调用它一次,你可以使用多态性。您还可以混合使用这两种技术来获得内部循环的高性能,同时在更高级别上易于使用。