设计模式适合模块化功能匹配应用程序? [英] Design pattern appropriate for a modular feature matching application?

查看:322
本文介绍了设计模式适合模块化功能匹配应用程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于我在这个问题(关于这个系统的实现),我希望如果我提出这个问题,我可以得到一些更好的建议。



我正在设计一个模块化应用程序,用于视频帧中的特征匹配(例如,在电影或视频的非常接近的帧中匹配,例如这篇文章,由Sivic,Zisserman)。



这个想法是允许在不同的特征检测算法以及不同的匹配程序之间轻松切换。另外,从我的研究中,我的理解是只有几个基本的匹配过程,而新的匹配方法主要集中在不匹配的附加修剪过程(例如同一篇文章)。所有的修剪过程都需要完成初始匹配,然后从基础和查询图像中通过匹配的进行附加的提取的特征的其他工作,拒绝






我设计的想法如下:




  • 实现基本界面 featureDetector

  • 所有具体的功能检测算法都继承自 featureDetector interface(例如 siftDetector

  • 实现基本界面 featureMatcher

  • 所有具体的匹配方法都继承自 featureMatcher 接口(例如对于OpenCV匹配器,如 cvMatcher )的类bruteForceMatcher 或)

  • 实现基本界面 imageMatcher 实施 策略 模式允许为所有匹配选择 featureDetector featureMatcher

  • 修剪程序,实现继承基本匹配界面的 装饰器 界面: class matcherDecorator:public imageMatcher

  • 每个附加的修剪/过滤程序实现 matcherDecorator spatialConsistencyFilter ),并且只包含具有 imageMatcher * 的构造函数作为(唯一)参数(表示要装饰的组件)



类型的成员对象 - 优先级 - 装饰师部分设计。每个 imageMatcher 应该保存来自两个图像(基本和查询)的提取的特征,以及 提取的特征。功能的内部表示与通过 imageMatcher 的公共访问功能向用户提供的功能描述符略有不同:

  class imageMatcher {
private://或protected:
...
...
std :: vector< internalFeatureDescriptor> ;技艺[2];
//不能超过500 - 1000个功能可以预期

std :: vector< std :: pair< int,int> >火柴;
// size与功能数量相同的数量级别
...
public:
std :: vector< userFriendlyFeatures> getFeatures(int baseOrQuery);
const std :: vector< std :: pair< int,int> > &安培; getMatches();
...
};

现在,由于特征向量(以及匹配向量)非常沉重,我当我使用它们时,不希望将它们复制到每个嵌套装饰器(过滤器)中。我没有与匹配向量的任何问题,因为它为用户提供了一个公共接口,允许装饰器访问引用,并省略复制数据的需要。另一方面,矢量不能提供这样的界面,而且他们的访问功能要求我不仅要复制,而且要重新计算功能的内部表示。这又导致装饰器需要访问内部超类指针的私有(或受保护)变量。



我设法允许我自己访问所需的向量,而不会违反任何隐私约束(我(认为)我没有做任何恶意实现),但是有人建议,访问超类的私有成员的想法违反了






所有这一切,我对任何有关如何重构的建议感兴趣我的代码,对我当前实现的意见和关于我的应用程序设计的任何其他事情。

解决方案

要实现过滤器作为函数/函子。



1:定义每个过滤器的接口/签名,例如为了过滤 matchResult 签名可以是:

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

(注意:您可能需要一个适用于专长的过滤器匹配



2:使用以下方式实现过滤器:




  • 继承/虚拟函数(类似于你的装饰器)

  • 作为c ++函子

  • As免费功能



3:将一个成员变量添加到 imageMatcher 注册过滤器



4:向您添加成员函数 imageMatcher 注册过滤器的类



5:实现您的 getMatches()成员函数,以便将每个注册的过滤器应用于匹配。如果您传递对匹配成员的引用,那么将应用每个过滤器来修改它。



假设选择一个函子基础方法



Covenience typedef

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

过滤器的签名是:

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

imageMatcher类看起来像:

  class imageMatcher {
private://或protected:
...
...
match_result matches;
// size与特征数量相同的数量级

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可以替换为旧版本的循环
for(auto& filt:match_filters)
{
/ /笔记匹配将被修改(见下面的注释)
filt(matches);
}
返回匹配;
}
};

过滤器可能如下所示:

  void DoSomeFiltering(match_result& matches)
{
//应用过滤器修改匹配
}
pre>

第二个过滤器可能是:

  struct ComplexFilter 
{
ComplexFilter(params ...);

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

过滤器注册如下:

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

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

注意: getFilteredMatches 与他们注册的顺序相同,每个过滤器直接修改匹配,这是你想要的?如果没有 getFilteredMatches 可以复制匹配,然后将过滤器应用于副本。然后,该副本返回值(注意,只有1个副本,返回的向量将被优化,即使在旧的c ++ 03编译器上)。



您可以你喜欢继承使用免费函数/函子。在这种情况下, match_filters 成员变量成为基类对象的向量,即

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

继承apporach可能更接近您当前的装饰器模式实现,减少需要执行的重构量。



我的感觉是使用装饰器模式直接修改对象的内部内容装饰不自然,因此可能需要解决方法才能访问受保护/私有数据。


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.

解决方案

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.

这篇关于设计模式适合模块化功能匹配应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆