zoukankan      html  css  js  c++  java
  • Opencv模板匹配

    一、

    1.模板匹配是一种最原始、最基本的模式识别方法,研究某一特定对象物的图案位于图像的什么地方,进而识别对象物,这就是一个匹配问题。

    它是图像处理中最基本、最常用的匹配方法。模板匹配具有自身的局限性,主要表现在它只能进行平行移动,若原图像中的匹配目标发生旋转或大小变化,该算法无效。

    2.painter.drawImage使用QImage::Format_RGB888格式的图像会出错,需要转换成Format_RGB32。

    img=image.convertToFormat(QImage::Format_RGB32);

    二、

    #ifndef MATCHTEMPLATEWIDGET_H
    #define MATCHTEMPLATEWIDGET_H
    
    #include <QObject>
    #include <QWidget>
    #include <QLabel>
    #include <QLineEdit>
    #include <QPushButton>
    #include <QComboBox>
    #include <QHBoxLayout>
    #include <QVBoxLayout>
    
    #include "opencv2/opencv.hpp"
    
    class MatchTemplateWidget : public QWidget
    {
        Q_OBJECT
    public:
        explicit MatchTemplateWidget(QWidget *parent = nullptr);
    public:
    //    enum TemplateMatchModes {
    //      TM_SQDIFF = 0,
    //      TM_SQDIFF_NORMED = 1,
    //      TM_CCORR = 2,
    //      TM_CCORR_NORMED = 3,
    //      TM_CCOEFF = 4,
    //      TM_CCOEFF_NORMED = 5
    //    };
    
         const int MatchMethodeNum=6;
         const QString MatchMethodeText[6]={"TM_SQDIFF 平方差匹配法","TM_SQDIFF_NORMED 标准平方差匹配","TM_CCORR 相关匹配法",
                                            "TM_CCORR_NORMED 标准相关匹配法","TM_CCOEFF 系数匹配法","TM_CCOEFF_NORMED 归一化相关系数匹配法"};
    signals:
    
    public slots:
    private slots:
        void slotSelectImageSource();
        void slotSelectImageTemplate();
        void slotStart();
    private:
    
        QLineEdit *leImageSource;
        QLineEdit *leImageTemplate;
        QLabel* lblDisplayImage;    
        QComboBox *cmbMatchMethode;
        void initUI();
        void matchTemplate(cv::TemplateMatchModes matchMethod);
        QImage matToQImage(cv::Mat mat);
    };
    
    #endif // MATCHTEMPLATEWIDGET_H
    #include "matchtemplatewidget.h"
    #include <QFileDialog>
    #include <QDebug>
    MatchTemplateWidget::MatchTemplateWidget(QWidget *parent)
        : QWidget(parent)
    {
        this->resize(600,400);
        initUI();
    }
    
    void MatchTemplateWidget::slotSelectImageSource()
    {
        QFileDialog *fileDialog = new QFileDialog(this);
        fileDialog->setWindowTitle(tr("Select File"));
        fileDialog->setDirectory(".");
        if(fileDialog->exec() == QDialog::Accepted)
        {
            QString imgPath = fileDialog->selectedFiles()[0];
            leImageSource->setText(fileDialog->selectedFiles()[0]);
        }
    }
    
    void MatchTemplateWidget::slotSelectImageTemplate()
    {
        QFileDialog *fileDialog = new QFileDialog(this);
        fileDialog->setWindowTitle(tr("Select File"));
        fileDialog->setDirectory(".");
        if(fileDialog->exec() == QDialog::Accepted)
        {
            QString imgPath = fileDialog->selectedFiles()[0];
            leImageTemplate->setText(fileDialog->selectedFiles()[0]);
        }
    
    }
    
    void MatchTemplateWidget::slotStart()
    {   
        matchTemplate((cv::TemplateMatchModes)cmbMatchMethode->currentIndex());
    }
    
    void MatchTemplateWidget::initUI()
    {
    
        QLabel *lblSourceText=new QLabel(this);
        lblSourceText->setText("Image Source:");
        lblSourceText->setMinimumSize(100,30);
        lblSourceText->setMaximumSize(100,30);
        leImageSource=new QLineEdit(this);
        QPushButton *btnSourceDlg=new QPushButton(this);
        btnSourceDlg->setText("...");
    
    
        QLabel *lblTemplateText=new QLabel(this);
        lblTemplateText->setMinimumSize(100,30);
        lblTemplateText->setMaximumSize(100,30);
        lblTemplateText->setText("Image Template:");
        leImageTemplate=new QLineEdit(this);
        QPushButton *btnTemplateDlg=new QPushButton(this);
        btnTemplateDlg->setText("...");
    
        cmbMatchMethode=new QComboBox(this);
        for(int i=0;i<MatchMethodeNum;i++)
        {
            cmbMatchMethode->addItem(MatchMethodeText[i]);
        }
    
        QPushButton *btnStart=new QPushButton("Start",this);
    
        lblDisplayImage=new QLabel(this);
    
        QHBoxLayout *h1=new QHBoxLayout();
        h1->addWidget(lblSourceText);
        h1->addWidget(leImageSource);
        h1->addWidget(btnSourceDlg);
    
        QHBoxLayout *h2=new QHBoxLayout();
        h2->addWidget(lblTemplateText);
        h2->addWidget(leImageTemplate);
        h2->addWidget(btnTemplateDlg);
    
        QHBoxLayout *h3=new QHBoxLayout();
        h3->addWidget(cmbMatchMethode);
        h3->addWidget(btnStart);
    
    
        QVBoxLayout *mainLayout=new QVBoxLayout(this);
        mainLayout->addLayout(h1);
        mainLayout->addLayout(h2);
        mainLayout->addLayout(h3);
        mainLayout->addWidget(lblDisplayImage);
        setLayout(mainLayout);
    
    
        connect(btnSourceDlg,SIGNAL(clicked()),SLOT(slotSelectImageSource()));
        connect(btnTemplateDlg,SIGNAL(clicked()),SLOT(slotSelectImageTemplate()));
        connect(btnStart,SIGNAL(clicked()),SLOT(slotStart()));
    
    }
    
    //TM_SQDIFF,TM_SQDIFF_NORMED匹配数值越低表示匹配效果越好,其它四种反之。
    //TM_SQDIFF_NORMED,TM_CCORR_NORMED,TM_CCOEFF_NORMED是标准化的匹配,得到的最大值,最小值范围在0~1之间,其它则需要自己对结果矩阵归一化。
    void MatchTemplateWidget::matchTemplate(cv::TemplateMatchModes matchMethod)
    {
        cv::Mat imgSource=cv::imread(leImageSource->text().toStdString());
        cv::Mat imgTemplate=cv::imread(leImageTemplate->text().toStdString());
    
        if(imgSource.cols==0||imgTemplate.cols==0)
        {
            return;
        }
    
    
        cv::Mat imgDisplay;
        imgSource.copyTo(imgDisplay);
    
    
        cv::Mat imgResult;
        int resultRows=imgSource.rows-imgTemplate.rows+1;
        int resultCols=imgSource.cols-imgTemplate.cols+1;
    
        imgResult.create(resultRows, resultCols, CV_32FC1 );
    
    
    
    
        cv::matchTemplate(imgSource,imgTemplate,imgResult,matchMethod);
    
    
        normalize(imgResult,imgResult,0,1,cv::NORM_MINMAX,-1,cv::Mat());
    
    
    
         double minVal;
         double maxVal;
         cv::Point minLoc;
         cv::Point maxLoc;
         cv::Point matchLoc;
    
         cv::minMaxLoc(imgResult, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat());
    
    
    
         if( matchMethod  == cv::TM_SQDIFF || matchMethod == cv::TM_SQDIFF_NORMED )
         {
             matchLoc = minLoc;
         }
         else
         {
             matchLoc = maxLoc;
         }
    
        cv::rectangle(imgDisplay,matchLoc,cv::Point(matchLoc.x + imgTemplate.cols , matchLoc.y + imgTemplate.rows), cv::Scalar(0,255,0), 2, 8, 0 );
        cv::rectangle(imgResult,matchLoc,cv::Point(matchLoc.x + imgTemplate.cols , matchLoc.y + imgTemplate.rows), cv::Scalar(0,255,0), 1, 8, 0 );
    
    
        QString text="minVal:"+QString::number(minVal)+" "+"maxVal:"+QString::number(maxVal);
    
        cv::putText(imgDisplay,text.toStdString(),cv::Point(30,30),cv::FONT_HERSHEY_SIMPLEX,1,cv::Scalar(255,0,0),2,cv::LINE_AA,false);
        lblDisplayImage->setPixmap(QPixmap::fromImage(matToQImage(imgDisplay)));
    
        //cv::imshow( "imgDisplay", imgDisplay);
        //cv::imshow( "imgResult", imgResult);
    
    }
    
    QImage MatchTemplateWidget::matToQImage(cv::Mat mat)
    {
        QImage img;
        int channels=mat.channels();
    
        if(channels==3)
        {
            cv::cvtColor(mat,mat,cv::COLOR_BGR2RGB);
            img = QImage(static_cast<uchar *>(mat.data),mat.cols,mat.rows,QImage::Format_RGB888);
        }
        else if(channels==4)
        {
           //argb
           img = QImage(static_cast<uchar *>(mat.data),mat.cols,mat.rows,QImage::Format_ARGB32);
        }
        else
        {
            //单通道,灰度图
           img = QImage(mat.cols, mat.rows,QImage::Format_Indexed8);
        }
    
        return img;
    }
  • 相关阅读:
    FPGA市场潜力有几多?
    FPGA前世今生(四)
    FPGA前世今生(三)
    FPGA前世今生(二)
    FPGA前世今生(一)
    嵌入式视频处理考虑(二)
    常用Linux操作命令
    混合开发学习路线
    Eclipse使用
    ECS的配置与使用
  • 原文地址:https://www.cnblogs.com/ike_li/p/12912131.html
Copyright © 2011-2022 走看看