OpenCV(C++)多目标模板匹配

原理

主要是在调用模板匹配函数后,生成了结果图,对结果图进行筛选,对于大于阈值并且不重叠的进行保留,最终实现多目标的匹配。对于判断不重叠的方式主要使用nms的方式。

nms:对于每个矩形框,从小到大进行排序,然后进行遍历从第二个开始判断与矩形框的list的每一个是否相交,相交则舍弃,否则保留,一下为代码实现,全部复制后进行编译即可运行,记得自己替换模板与图片路径。

代码

所需的头文件

#include <opencv2/opencv.hpp>
#include <algorithm>

结构体的定义,方便保存数据

/**
 * @author stf
 * @brief nms data struct
 * @date 2022-12-27
 * @param val match template min val
 * @param loc match template min loc
 * @param roi match template result rect roi
 * @param getRect Function:use loc and temp size to calibrate roi
**/
struct nms_data_struct
{
    float val;
    cv::Point loc;
    cv::Rect roi;

    void getRect(cv::Size temp_size)
    {
        roi=cv::Rect(loc.x,loc.y,temp_size.width,temp_size.height);
    }
};

函数编写,其中,comp函数是比较函数,使用algorithm方法;nms_detect函数是判断两个矩形是否相交,相交则直接舍弃,否则保留;nms_temp_min是主要实现函数,最后以图片形式保存结果

/**
 * @author stf
 * @date 2022-12-27
 * @brief sort compare function
**/
bool comp(nms_data_struct data1,nms_data_struct data2)
{
    return data1.val<data2.val;
}

/**
 * @author stf
 * @brief nms detect if rect is overlap
 * @date 2022-12-27
 * @param data Contains the structure of the matrix to be judged
 * @param data_list rect list for judged
 * @return true:the rect is not overlap,false:the rect is overlap
**/
int nms_detect(nms_data_struct data,std::vector<nms_data_struct> data_list)
{
    for(int i=0;i<data_list.size();i++)
    {
        cv::Rect rect=data.roi&data_list[i].roi;
        if(rect.width||rect.height)
            return false;
    }
    return true;
}
/**
 * @author stf
 * @brief nms to calibrate min match template
 * @date 2022-12-27
 * @param input optional,to draw on this img
 * @param result matchTemplate result img
 * @param temp_size template image size
 * @param save_output whether use save output
 * @param thr min threshold 
 * @return 0 It's fixed at the moment,You can add a judgment to return other
**/
int nms_temp_min(cv::Mat &input,cv::Mat result,cv::Size temp_size,bool save_output=true,float thr=0.03)
{
    // get minVal vector and minLoc vector
    std::vector<nms_data_struct> nms_data;
    for(int i=0;i<result.cols;i++)
    {
        for(int j=0;j<result.rows;j++)
        {
            if(result.at<float>(j,i)<=thr)
            {
                nms_data_struct data;
                data.val=result.at<float>(j,i);
                data.loc=cv::Point(i,j);
                data.getRect(temp_size);
                nms_data.push_back(data);
            }
        }
    }

    //Sort from smallest to largest
    std::sort(nms_data.begin(),nms_data.end(),comp);

    //nms
    std::vector<nms_data_struct> nms_output_list;  
    for(int i=0;i<nms_data.size();i++)
    {
        if(i==0)
        {
            nms_data_struct data;
            data.val=nms_data[i].val;
            data.loc=nms_data[i].loc;
            data.roi=nms_data[i].roi;
            nms_output_list.push_back(data);
            continue;
        }

        int ret=nms_detect(nms_data[i],nms_output_list);
        if(ret)
        {
            nms_data_struct data;
            data.val=nms_data[i].val;
            data.loc=nms_data[i].loc;
            data.getRect(temp_size);
            nms_output_list.push_back(data);   
        }
    }

    //save output in current path
    if(save_output)
    {
        for(int i=0;i<nms_output_list.size();i++)
        {
            cv::rectangle(input,nms_output_list[i].roi,cv::Scalar(0,255,0));
            cv::Size text_size=cv::getTextSize(std::to_string(nms_output_list[i].val),cv::FONT_HERSHEY_COMPLEX,1.0f,1,(int *)int());
            cv::rectangle(input,cv::Rect(nms_output_list[i].loc.x,nms_output_list[i].loc.y-text_size.height,text_size.width,\
                          text_size.height),cv::Scalar(0,255,0),-1);
            cv::putText(input,std::to_string(nms_output_list[i].val),nms_output_list[i].loc,cv::FONT_HERSHEY_COMPLEX,1.0f,\
                        cv::Scalar(0,0,0));

        }
        cv::imwrite("../nms_output.jpg",input);
    }

    return 0;
}

主函数编写,调用以上函数

int main()
{
    cv::Mat img=cv::imread("../b1.jpg");
    cv::Mat temp=cv::imread("../temp_bd.jpg");

    cv::Mat result;
    cv::matchTemplate(img,temp,result,1);
    nms_temp_min(img,result,temp.size(),true,0.06);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36076137/article/details/128465936