何为模板匹配
模板匹配就是在指定模板图片中,在模板区域内找寻与待匹配图片中最相似的。通过不断滑动模板图片,计算其与待匹配图片区域的匹配度,将匹配度最高区域视为最终匹配结果。
实现方法
Imgproc.matchTemplate(src, template, result, method);
参考示例
package com.polar.core.bdata.templateMatch;
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import java.util.HashMap;
import java.util.Map;
/**
* 描述: OpenCv匹配图像模板工具类
* 创建时间:2023/1/30 11:18
* @author Perpetual
*/
public class OpenCVUtil{
//静态代码块加载动态链接库
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
/**
* 描述:通过图片地址进行图片比对方法
* 作者:Perpetual
* 创建时间:2023/1/30 11:19
* @param mainPic 待匹配图片-主模板
* @param comPic 获取匹配模板-图片模块
* @return code == 200/500 比对成功/比对失败(成功包含x/y/itemWidth/itemHeight)
*/
public static Map<String, Object> getCoordinates(String mainPic, String comPic) {
Map<String, Object> reason = new HashMap<>();
try {
// 读入的模式
// 模式 说明
// IMREAD_UNCHANGED 按原样返回加载的图像(使用alpha通道,否则会被裁剪)。
// IMREAD_GRAYSCALE 将图像转换为单通道灰度图像(编解码器内部转换)。
// IMREAD_COLOR 将图像转换为3通道BGR彩色图像。
// IMREAD_ANYDEPTH 当输入图像具有深度时,返回16位/32位图像,否则将其转换为8位。
// IMREAD_ANYCOLOR 图像以任何可能的颜色格式读取。
// IMREAD_LOAD_GDAL 使用gdal驱动程序加载图像。
// IMREAD_REDUCED_GRAYSCALE_2 将图像转换为单通道灰度图像,图像大小缩小1/2。
// IMREAD_REDUCED_COLOR_2 将图像转换为3通道BGR彩色图像,图像大小缩小1/2。
// IMREAD_REDUCED_GRAYSCALE_4 将图像转换为单通道灰度图像,图像大小缩小1/4。
// IMREAD_REDUCED_COLOR_4 始终将图像转换为3通道BGR彩色图像,图像大小缩小1/4。
// IMREAD_REDUCED_GRAYSCALE_8 始终将图像转换为单通道灰度图像,图像大小减小1/8。
// IMREAD_REDUCED_COLOR_8 将图像转换为3通道BGR彩色图像,图像大小缩小1/8。
// IMREAD_IGNORE_ORIENTATION 不要根据EXIF的方向标志旋转图像。
// 待匹配图片---主模板
Mat src = Imgcodecs.imread(mainPic);
// 获取匹配模板---图片模块
Mat template = Imgcodecs.imread(comPic);
/*
* TM_SQDIFF = 0, 平方差匹配法,最好的匹配为0,值越大匹配越差
* TM_SQDIFF_NORMED = 1,归一化平方差匹配法
* TM_CCORR = 2,相关匹配法,采用乘法操作,数值越大表明匹配越好
* TM_CCORR_NORMED = 3,归一化相关匹配法
* TM_CCOEFF = 4,相关系数匹配法,最好的匹配为1,-1表示最差的匹配
* TM_CCOEFF_NORMED = 5;归一化相关系数匹配法
*/
int method = Imgproc.TM_CCOEFF;
int width = src.cols() - template.cols() + 1;
int height = src.rows() - template.rows() + 1;
// 创建32位模板匹配结果Mat
Mat result = new Mat(width, height, CvType.CV_32FC1);
/*
* 将模板与重叠的图像区域进行比较。
* @param src运行搜索的图像。 它必须是8位或32位浮点。
* @param template。 它必须不大于源图像并且具有相同的数据类型。
* @param result比较结果图。 它必须是单通道32位浮点。 如果image是(W * H)并且templ是(w * h),则结果是((W-w + 1)*(H-h + 1))。
* @param方法用于指定比较方法的参数,请参阅默认情况下未设置的#TemplateMatchModes。
* 当前,仅支持#TM_SQDIFF和#TM_CCORR_NORMED方法。
*/
Imgproc.matchTemplate(src, template, result, method);
// 归一化
Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());
// 获取模板匹配结果
Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
double x = mmr.minLoc.x;
double y = mmr.minLoc.y;
/*
* FILLED = -1,
* LINE_4 = 4, 下一个点和上一个点边相连(没有角了),这样就消除了8联通法线断裂的瑕疵
* LINE_8 = 8, 下一个点连接上一个点的边或角
* LINE_AA = 16; 边缘像素采用高斯滤波,抗锯齿
*/
Imgproc.rectangle(src,new Point(x,y),new Point(x+template.cols(),y+template.rows()),new Scalar( 0, 0, 255),2,Imgproc.LINE_4);
// Imgproc.rectangle(template,new Point(0,0),new Point(template.cols(),template.rows()),new Scalar( 0, 0, 255),2,Imgproc.INTER_LINEAR_EXACT);
// HighGui.imshow("wda",template);
HighGui.imshow("对比结果", src);
} catch (Exception e) {
e.printStackTrace();
}
}
}
对比结果
1 模板图片:
2 待匹配区域图片
3 对比结果