模板匹配是一项在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术。利用给定的已知模板与待匹配的图像或数组计算匹配度,以达到寻找目标的目的。模板可以是矩形块也可以是一维数组,如果模板是一个矩阵,一般待匹配的数据也矩阵,如果模板是一个一维数据,那么待匹配的数据也最好是一维数据。模板匹配在图像处理中应用较为广泛,如通过设置匹配度的阈值用在异常检测中,通过阈值设定寻找给定的目标等等。
前言
越来越多的开发人员选择基于开源的Qt框架与OpenCV来实现界面和算法,其原因不单单是无版权问题,更多是两个社区的发展蓬勃,可用来学习的资料与例程特别丰富。以下是关于利用Qt构建GUI并使用OpenCV中的matchTemplate/minMaxLoc函数进行图像的模板匹配。
软件版本:Qt-5.12.0/OpenCV-4.5.3
平台:Windows10/11–64
一、函数介绍
1、matchTemplate
函数原型:
cv::matchTemplate(InputArray image, InputArray templ, OutputArray result, int method );
参数解释:
image:是输入图像,一般是Mat类数组;
templ:是模板数据,一般也是Mat类数组,长宽必须小于输入图像image的长宽;
result:是输出结果,大小为(w1-w2+1,h1-h2+1),其中w1为输入图像image的宽,w2为模板的宽,h1为输入图像image的高,h2为模板的高;
method:是模板匹配的匹配计算方式,可设置的参数有:
TM_SQDIFF:平均差匹配法
TM_SQDIFF_NORMED:归一化平均差匹配法
TM_CCORR:相关匹配法
TM_CCORR_NORMED:归一化相关匹配法
TM_CCOEFF:系数匹配法
TM_CCOEFF_NORMED:归一化系数匹配法
2、minMaxLoc
函数原型:
cv::minMaxLoc(const SparseMat& src, double* minVal, double* maxVal, int* minIdx=0, int* maxIdx=0);
参数解释:
src:输入单通道数组(图像);
minVal:返回最小值的指针,若无须返回,此值置为NULL;
maxVal:返回最大值的指针,若无须返回,此值置为NULL;
minLoc:返回最小位置的指针(二维情况下),若无须返回,此值置为NULL;
maxLoc:返回最大位置的指针(二维情况下),若无须返回,此值置为NULL;
mask:用于选择子阵列的可选掩膜;
二、演示
1、GUI
如上图创建Method的QComboBox控件进行选择,Template的PushButton按钮选择掩膜,Match的PushButton按钮执行,对当前窗口的图像进行模板检测,并输出状态信息。
2、代码实现
matchBtn的clicked()槽函数的实现代码如下:
void MainWindow::on_matchBtn_clicked() { std::size_t numView = ui->tabWidget->currentIndex() % 3; if (dispMat[numView]->empty()) { outputInfo(2, tr("Please make sure the Mat exist!")); return; } QString fileName = ui->templateLineEdit->text(); cv::Mat templateMat; if (!fileName.isEmpty()) { templateMat = cv::imread(fileName.toStdString()); if (templateMat.empty()) { outputInfo(2, tr("Please make sure the template exist.")); return; } else { outputInfo(1, tr("Template Mat success.")); } } else { outputInfo(2, tr("Please make sure the template file name exist.")); return; } *tmpMat = dispMat[numView]->clone(); int matchMethod = ui->matchCombo->currentIndex(); int resultCols = tmpMat->cols - templateMat.cols + 1; int resultRows = tmpMat->rows - templateMat.rows + 1; cv::Mat resultMat = cv::Mat::zeros(resultCols, \ resultRows, \ tmpMat->type()); double startTime = static_cast<double>(cv::getTickCount()); cv::matchTemplate(*tmpMat, templateMat, resultMat, matchMethod); cv::normalize(resultMat, resultMat, 0, 1, cv::NORM_MINMAX, -1, \ cv::Mat()); double timeCost = (static_cast<double>(cv::getTickCount()) - \ startTime) / cv::getTickFrequency(); QString costTime = "Cost time: " + QString::number(timeCost); outputInfo(1, costTime); double minVal, maxVal; cv::Point maxLoc, minLoc, matchLoc; cv::minMaxLoc(resultMat, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat()); /* if (matchMethod < 2) { matchLoc = minLoc; } else { matchLoc = maxLoc; } */ matchLoc = (matchMethod < 2) ? minLoc : maxLoc; cv::rectangle(*tmpMat, matchLoc, \ cv::Point(matchLoc.x + templateMat.cols, \ matchLoc.y + templateMat.rows), \ cv::Scalar::all(0), 2, 8, 0); if (ui->matchChkBox->isChecked()) { *dispMat[numView] = tmpMat->clone(); cvtMatPixmap(dispMat, dispPixmap, numView); } else { if (tmpMat->channels() == 3) { QImage tmpImage = QImage(tmpMat->data, tmpMat->cols,tmpMat->rows, \ static_cast<int>(tmpMat->step), \ QImage::Format_RGB888); dispPixmap[numView]->setPixmap(QPixmap::fromImage(tmpImage.rgbSwapped())); } else { QImage tmpImage = QImage(tmpMat->data, tmpMat->cols,tmpMat->rows, \ static_cast<int>(tmpMat->step), \ QImage::Format_Grayscale8); dispPixmap[numView]->setPixmap(QPixmap::fromImage(tmpImage.rgbSwapped())); } } outputInfo(1, tr("Match done.")); std::stringstream tmpStream; std::streambuf* coutBuf = std::cout.rdbuf(); std::cout.rdbuf(tmpStream.rdbuf()); std::cout << " matchLoc: " << matchLoc << std::endl; std::string matchLocString(tmpStream.str()); std::cout.rdbuf(coutBuf); QString matchLocInfo = QString::fromStdString(matchLocString); int x = matchLoc.x; int y = matchLoc.y; ui->matchLineEdit->setText(QString::number(x) + "," \ + QString::number(y) + "," \ + QString::number(templateMat.cols + x) + "," \ + QString::number(templateMat.rows + y)); outputInfo(1, matchLocInfo); }
总结
以上是关于利用Qt进行GUI构建并使用OpenCV中的matchTemplate/minMaxLoc函数进行图像的模板匹配。