Design pattern appropriate for a modular feature matching application?

本小妞迷上赌 提交于 2019-12-13 03:48:30

问题


Since I got some negative comments on my system design on this question (concerning the implementation of such system), I hope that if I present the problem I could get some better suggestions.

I am trying to design a modular application to be used for feature matching in video frames (e.g. matching on very close frames of a movie or a video, like "the product" in this article by Sivic, Zisserman).

The idea is to allow for an easy switch between different feature detection algorithms as well as different matching procedures. Additionally, from my research, my understanding is that there is only a few basic matching procedures, while new matching methods mainly focus on additional pruning procedures for bad matches (e.g. spatial consistency in the same article). All the pruning procedures require for the initial matching to be done, and then do some additional work on the extracted features from the base and query images coupled by the matching, rejecting the bad matches.


The idea I had for the design is as follows:

  • implement a base interface featureDetector
  • all concrete feature detection algorithms inherit from featureDetector interface (e.g. siftDetector)
  • implement a base interface featureMatcher
  • all concrete matching methods inherit from the featureMatcher interface (e.g. class bruteForceMatcher or wrappers for OpenCV matchers like cvMatcher)
  • implement a base interface imageMatcher implementing a Strategy pattern to allow for a choice of featureDetector and featureMatcher
  • for all the matching pruning procedures, implement a Decorator interface that inherits the base matching interface: class matcherDecorator : public imageMatcher
  • each additional pruning / filtering procedure implements the matcherDecorator interface (e.g. spatialConsistencyFilter) and contains only the constructor with imageMatcher* as the (only) argument (representing the component to be decorated)

The problems pointed out to me in this question arise from the specific results of the feature detection and matching process, and they concern the Decorator part of the design. Each imageMatcher should hold extracted features from both of the images (base and query), as well as the matches between the extracted features. The internal representation of features is slightly different from the feature descriptors offered to the user via the public access function of imageMatcher:

class imageMatcher{
    private: // or protected:
        ...
        ...
        std::vector <internalFeatureDescriptor> feats[2];
            // no more than 500 - 1000 features can be expected

        std::vector <std::pair <int, int> > matches;
            // size is the same order of magnitude as the number of features
        ...
    public:
        std::vector <userFriendlyFeatures> getFeatures(int baseOrQuery);
        const std::vector <std::pair<int, int> > &getMatches();
        ...
};

Now, since the feature vectors (as well as the matches vector) are quite "heavy", I would not like to copy them in to each one of the nested decorators (filters) when I use them. I do not have any problems with the matches vector, since it offers a public interface for the user allowing the decorator access to the reference and omitting the need to copy the data. feats vectors, on the other hand, do not offer such an interface, and their access function requires me to do not only copying, but also recalculation of features' internal representation. This in turn results in the need for the decorator to access the private (or protected) variables of the inner superclass pointer.

I managed to grant my self access to the needed vectors without violating any privacy constraints (I (think) I'm not doing anything evil implementationaly), but it has been suggested that the very idea of accessing the private members of the superclass violates the idea of the Decorator pattern.


All that said, I am interested in any suggestions about how to refactor my code, comments on my current implementation and anything else concerning the design of my application.


回答1:


An alternative to the decorator pattern would be to implement the filters as functions / functors.

1: Define the interface / signature of each filter, e.g. for filtering matchResult the signature could be:

std::function<void (std::vector <std::pair <int, int> >& )>

(Note: you may want a filter that works on feats and matches)

2: Implement the filters using:

  • Inheritance / Virtual functions (similar to your decorator)
  • As c++ functors
  • As free functions

3: Add a member variable to your imageMatcher class for stroing registered filters

4: Add member functions to you imageMatcher class for registering filters

5: Implement your getMatches() member function such that it applies each registered filter to the matches. If you pass a reference to thematches member it will be modified as each filter is applied.

Example, assuming that a functor base approach is chosen

Covenience typedef

typdef std::vector <std::pair <int, int> > match_result;

The signature of the filter is:

typedef std::function< void (match_result& )> match_filter_type;

The `imageMatcher' class would look something like:

class imageMatcher{
    private: // or protected:
        ...
        ...
        match_result matches;
        // size is the same order of magnitude as the number of features

        std::vector< match_filter_type > match_filters;
    ...
    public:
        imageMatcher& registerMatchFilter( match_filter_type filter )
        {
            match_filters.push_back( filter );
            return *this;
        }

        const std::vector <std::pair<int, int> > &getFilteredMatches()
        {
          // c++11 could be replaced with older style for loop
          for( auto& filt: match_filters)  
          {
            // note matches will be modified (see note below)
            filt( matches );
          }
          return matches;
        }
   };

A filter may look like:

void DoSomeFiltering( match_result& matches )
{
    // apply the filter modifying matches
}

A second filter might be:

struct ComplexFilter
{
   ComplexFilter( params... );  

   void operator()( match_result& matches );
};

Filters are registered as follows:

myImageMatcher.registerMatchFilter( ComplexFilter( args... ) );

// call chaining
myImageMatcher.registerMatchFilter( AnotherFilter( args... ) )
              .registerMatchFilter( OneMoreFilter( args... ) )
              .registerMatchFilter( FilterXXX( args... ) );

Note: getFilteredMatches applies the filters in the same order as they were registered, with each filter directly modifying the matches, is this what you want? If not getFilteredMatches could make a copy of matches and then apply the filters to the copy. The copy is then returned by value (note there will only be 1 copy, the returned vector will be optimised away even on older c++03 compilers).

You may decde that you prefer inheritance to using free functions / functors. In that case the match_filters member variable becomes a vector of base class objects i.e.

class MatchFilterBase;
std::vector< std::shared_ptr<MatchFilterBase> >  match_filters;

The inheritance apporach may be closer to your current decorator pattern implementation, reducing that amount of refactoring that needs to be performed.

My feeling is that use of the decorator pattern to directly modify the internal contents of the object being decorated does not feel natural, hence it might require workarounds to gain access to protected / private data.



来源:https://stackoverflow.com/questions/10007600/design-pattern-appropriate-for-a-modular-feature-matching-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!