void AddControlPointsWithCheck(CPVector &cpv, CPVector &new_cp, Panorama *pano=NULL)
{
    for(unsigned int i=0;i<new_cp.size();i++)
    {
        HuginBase::ControlPoint cp=new_cp[i];
        bool duplicate=false;
        for(unsigned int j=0;j<cpv.size();j++)
        {
            if(cp==cpv[j])
            {
                duplicate=true;
                break;
            }
        };
        if(!duplicate)
        {
            cpv.push_back(cp);
            if(pano!=NULL)
                pano->addCtrlPoint(cp);
        };
    };
};
CPVector AutoPanoSiftMultiRowStack::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs,
                                     int nFeatures, int & ret_value, wxWindow *parent)
{
    CPVector cps;
    if (imgs.size() == 0) {
        return cps;
    };
    std::vector<stack_img> stack_images;
    HuginBase::StandardImageVariableGroups* variable_groups = new HuginBase::StandardImageVariableGroups(pano);
    for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++)
    {
        unsigned int stack_nr=variable_groups->getStacks().getPartNumber(*it);
        //check, if this stack is already in list
        bool found=false;
        unsigned int index=0;
        for(index=0;index<stack_images.size();index++)
        {
            found=(stack_images[index].layer_nr==stack_nr);
            if(found)
                break;
        };
        if(!found)
        {
            //new stack
            stack_images.resize(stack_images.size()+1);
            index=stack_images.size()-1;
            //add new stack
            stack_images[index].layer_nr=stack_nr;
        };
        //add new image
        unsigned int new_image_index=stack_images[index].images.size();
        stack_images[index].images.resize(new_image_index+1);
        stack_images[index].images[new_image_index].img_nr=*it;
        stack_images[index].images[new_image_index].ev=pano.getImage(*it).getExposure();
    };
    delete variable_groups;
    //get image with median exposure for search with cp generator
    UIntSet images_layer;
    for(unsigned int i=0;i<stack_images.size();i++)
    {
        std::sort(stack_images[i].images.begin(),stack_images[i].images.end(),sort_img_ev);
        unsigned int index=0;
        if(stack_images[i].images[0].ev!=stack_images[i].images[stack_images[i].images.size()-1].ev)
        {
            index=stack_images[i].images.size() / 2;
        };
        images_layer.insert(stack_images[i].images[index].img_nr);
    };
    ret_value=0;
    //work on all stacks
    if(!setting.GetProgStack().IsEmpty())
    {
        CPDetectorSetting stack_setting;
        stack_setting.SetType(CPDetector_AutoPanoSift);
        stack_setting.SetProg(setting.GetProgStack());
        stack_setting.SetArgs(setting.GetArgsStack());

        for(unsigned int i=0;i<stack_images.size();i++)
        {
            UIntSet images_stack;
            images_stack.clear();
            for(unsigned int j=0;j<stack_images[i].images.size();j++)
                images_stack.insert(stack_images[i].images[j].img_nr);
            if(images_stack.size()>1)
            {
                AutoPanoSift matcher;
                CPVector new_cps=matcher.automatch(stack_setting, pano, images_stack, nFeatures, ret_value, parent);
                if(new_cps.size()>0)
                    AddControlPointsWithCheck(cps,new_cps);
                if(ret_value!=0)
                {
                    std::vector<wxString> emptyKeyfiles;
                    Cleanup(setting, pano, imgs, emptyKeyfiles, parent);
                    return cps;
                };
            };
        };
    }
    //generate cp for median exposure with multi-row algorithm
    if(images_layer.size()>1)
    {
        UIntSet allImgs;
        fill_set(allImgs, 0, pano.getNrOfImages()-1);
        Panorama newPano=pano.getSubset(allImgs);
        if(cps.size()>0)
            for (CPVector::const_iterator it=cps.begin();it!=cps.end();++it)
                newPano.addCtrlPoint(*it);

        AutoPanoSiftMultiRow matcher;
        CPVector new_cps=matcher.automatch(setting, newPano, images_layer, nFeatures, ret_value, parent);
        if(new_cps.size()>0)
            AddControlPointsWithCheck(cps,new_cps);
    };
    return cps;
};