2011-10-29 4 views
0

私は自分でデジタル画像処理を勉強していますが、polymorphismをこのアプリケーションに適用する必要があるかどうか、またはより優れたクラスデザインがあるかどうかを誰かがコメントできれば本当に感謝します。ケーススタディ:画像処理の多態性

基本的に、2Dフィルタ/カーネルは、non-separableまたはseparableのいずれかです。重要なカーネル操作はconvolutionであり、計算方法はフィルターの種類によって異なります。でもCSeparableKernel2Dクラスは、2つのプライベートメンバを持つことができ

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

注:CKernel1D<T> m_X, m_YCKernel1D<T>クラスは、独自のmyConvolutionメソッドを持つことができます。つまり、myConvolutionRows,myConvolutionColsです。

また、通常は、与えられた画像にfilters(分離可能/分離不可能)のセットを適用したい、すなわち、入力画像が与えられた場合にはfilterと畳み込みます。したがって、filter typeに応じて、対応するmyConvolutionメソッドを呼び出す必要があります。

(1)sthを行うには、最もクリーンな方法が必要です。好き?

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タイプに応じて呼び出されます。どのように私はそのような操作を達成できますか?私はsthを読む。 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; 
} 

新世代のコンパイラは非常によく、このコードを最適化することができます:)オーバーヘッドが、あなたは良いコンパイラを使用していて、リリースモードでコンパイルし、ゼロになります。

もちろん、内部ファンクタを1000回呼び出す必要がある場合は、一度呼び出す必要がある場合は、これを多面的に使うことができます。 両方の手法を混在させて、内側ループで高性能を達成し、同時に高レベルで使いやすさを向上させることもできます。

+0

あなたの投稿に感謝します。私は静的にリンクされたコードを使ったことは一度もありません。さらに、私の場合、 'NegateTransformer'のようなクラスは、例えば、特定の'カーネル型 'に対応します。 'Transform'メソッドは' convolution'であり、 'ArrayTransformer'は' Kernel2D 'でしょうか? – Tin

+0

@マーク、多形関数は、 'カーネル畳み込み 'ごとに1回だけ呼び出されます。 'implementation'では、ピクセルを処理するいくつかの入れ子になったループがあります。 – Tin