一、图像模板匹配
所谓模板匹配,就是给定一张模板图像,在目标图像中搜索与模板图像内容最相似或最一致的区域,并确定其位置。它本质上是一种局部区域比对技术,常用于目标定位、缺陷检测、字符识别、零件检测等场景。
1、图像模板匹配原理
可以把模板匹配理解成:
拿着一张“小图片(模板)”,在“大图片(目标图像)”上逐块滑动,寻找最像的位置。
2、图像模板匹配函数
/* 用途:用于在大图像中查找与模板图像最相似的位置, 通过让模板在原图上逐像素滑动,并计算每个位置的相似度或差异值, 最终得到最佳匹配区域 */ void cv::matchTemplate( InputArray image, InputArray templ, OutputArray result, int method, InputArray mask = noArray() ); /* image:待模板匹配的原图像,图像数据类型为CV_8U和CV_32F两者中的一个 templ:模板图像,需要与image具有相同的数据类型,但是尺寸不能大于image result:模板匹配结果输出图像,图像数据类型为CV_32F。如果image的尺寸为W * H, 模板图像尺寸为w * h,则输出图像的尺寸为(W - w + 1) * (H - h + 1) method:模板匹配方法标志 mask:匹配模板的掩码,必须与模板图像具有相同的数据类型和尺寸,默认情况下不设置, 目前仅支持在TM_SQDIFF和TM_CCORR_NORMED这两种匹配方法时使用 */| 标志参数 | 简记 | 作用 |
|---|---|---|
| TM_SQDIFF | 0 | 平方差匹配法(相似为0,不相似为较大值) |
| TM_SQDIFF_NORMED | 1 | 归一化平方差匹配法(相似为0,不相似为1) |
| TM_CCORR | 2 | 相关匹配法(数值越大越相似) |
| TM_CCORR_NORMED | 3 | 归一化相关匹配法(最佳匹配为1) |
| TM_CCOEFF | 4 | 系数匹配法(数值越大越相似) |
| TM_CCOEFF_NORMED | 5 | 归一化相关系数匹配法(最佳匹配为1) |
3、示例代码
QString imgPath = QApplication::applicationDirPath() + "/Images"; cv::String s_imgPath = imgPath.toLocal8Bit().data(); Mat img = imread(s_imgPath + "/lena.jpg"); Mat temp = imread(s_imgPath + "/lena_face.jpg"); if (img.empty() || temp.empty()) { qDebug() << "图片加载失败, 请确认图像文件名称是否正确"; return; } Mat result; matchTemplate(img, temp, result, TM_CCOEFF_NORMED); double maxVal, minVal; Point maxLoc, minLoc; minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc); rectangle(img, Point(maxLoc.x, maxLoc.y), Point(maxLoc.x + temp.cols, maxLoc.y + temp.rows), Scalar(0, 255, 0), 5); imshow("img", img); imshow("temp", temp); imshow("result", result); waitKey(0); destroyAllWindows();二、图像卷积
卷积核是一个n × n 的矩阵,其中n 通常为奇数(如 3、5、7 等),这样卷积核才能拥有唯一的中心点,便于在图像上进行滑动计算。卷积运算时,卷积核的中心点会对准当前处理的像素位置,再结合周围邻域像素共同计算新的像素值。
卷积核中的每一个数字都表示一个权重系数,用于描述对应位置像素对中心像素的影响程度。权重越大,说明该位置像素对结果贡献越大;权重为负数时,通常用于增强边缘、检测变化区域等操作。
1、图像卷积原理
- 图像卷积主要步骤:
- 将卷积模板旋转180°
- 卷积模板移动到对应位置
- 卷积内求和,保存求和结果
- 滑动卷积模板,处理所有位置
2、图像卷积函数
/* 用途:用于对图像执行二维卷积滤波操作,即让卷积核在图像上逐像素滑动, 并根据邻域像素与核权重计算新的像素值,从而实现图像增强或特征提取 */ void cv::filter2D( InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor = Point(-1,-1), double delta = 0, int borderType = BORDER_DEFAULT ); /* src:输入图像 dst:输出图像,与输入图像具有相同的尺寸和通道数 ddepth:输出图像的数据类型(深度),根据输入图像的数据类型不同拥有不同的取值范围 kernel:卷积核,CV_32FC1类型的矩阵 anchor:内核的基准点(锚点),默认值(-1,-1)代表内核基准点位于kernel的中心位置 delta:偏值,在计算结果中加上偏值 borderType:像素外推法选择标志 */3、示例代码
/*待卷积矩阵*/ uchar points[25] = { 1,2,3,4,5, 6,7,8,9,10, 11,12,13,14,15, 16,17,18,19,20, 21,22,23,24,25 }; Mat img(5, 5, CV_8UC1, points); /*卷积模板*/ Mat kernel = (Mat_<float>(3, 3) << 1, 2, 1, 2, 0, 2, 1, 2, 1); Mat kernel_norm = kernel / 12;/*卷积模板归一化*/ Mat result, result_norm;/*未归一化卷积结果和归一化卷积结果*/ filter2D(img, result, CV_32F, kernel, Point(-1, -1), 2, BORDER_CONSTANT); filter2D(img, result_norm, CV_32F, kernel_norm, Point(-1, -1), 2, BORDER_CONSTANT); cout << "result: " << endl << result << endl; cout << "result_norm: " << endl << result_norm << endl; /*图像卷积*/ QString imgPath = QApplication::applicationDirPath() + "/Images"; cv::String s_imgPath = imgPath.toLocal8Bit().data(); Mat lena = imread(s_imgPath + "/lena.jpg"); if (lena.empty()) { qDebug() << "图片加载失败, 请确认图像文件名称是否正确"; return; } Mat lena_filter; filter2D(lena, lena_filter, -1, kernel_norm, Point(-1, -1), 2, BORDER_CONSTANT); imshow("lena_filter", lena_filter); imshow("lena", lena); waitKey(0); destroyAllWindows();