0%

【OpenCV】使用 OpenCv 进行图片模板匹配

使用OpenCv在输入图片中匹配模板图片的位置

前言

  做一个项目需要在Android中定位目标位置,现已经可以得到Android屏幕状态,于是需要一个方法来实现这个定位功能,自己也写过1个定位的方法奈何反应太慢,在网上找资料时发现OpenCv已经实现此功能,可以直接使用,欣喜若狂,特此记录一下。

OpenCv是什么?

  • OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉和机器学习软件库。
  • OpenCV是用于图像处理、分析、机器视觉方面的开源函数库.

测试用例

随便找个图片作为输入

随便截取一部分作为模板

需求描述

至此我们需求为在输入图片中匹配寻找模板图片,如下图:

实现步骤

拿到Mat实例

1
2
Mat m_input = Imgcodecs.imread(input_path);//输入
Mat m_template = Imgcodecs.imread(template_path);//模板

创建比较结果图

1
2
3
int result_rows = m_input.rows() - m_template.rows() + 1;
int result_cols = m_input.cols() - m_template.cols() + 1;
Mat g_result = new Mat(result_rows, result_cols, CvType.CV_32FC1);

调用 matchTemplate() 进行模板匹配

1
Imgproc.matchTemplate(m_target, m_template, g_result, Imgproc.TM_CCORR_NORMED);

将结果图进行归一化

1
Core.normalize(g_result, g_result, 0, 1, Core.NORM_MINMAX, -1, new Mat());
  • 归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。
  • 归一化是为了后面数据处理的方便,其次是保证程序运行时收敛加快
  • 归一化的具体作用是归纳统一样本的统计分布性
  • 归一化在0-1之间是统计的概率分布,归一化在某个区间上是统计的坐标分布。
  • 归一化有同一、统一和合一的意思。
  • 归一化的目的,是使得没有可比性的数据变得具有可比性同时又保持相比较的两个数据之间的相对关系,如大小关系;或是为了作图,原来很难在一张图上作出来,归一化后就可以很方便的给出图上的相对位置等。

得到模板位置

1
2
3
Core.MinMaxLocResult mmlr = Core.minMaxLoc(g_result);
Point matchLocation = mmlr.maxLoc; // 此处使用maxLoc还是minLoc取决于使用的匹配算法
System.out.println(matchLocation.x + "-----" + matchLocation.y);

返回模板的中间坐标

1
2
3
4
double x = matchLocation.x + (m_template.cols() / 2);
double y = matchLocation.y + (m_template.rows() / 2);
double[] tile = {x, y};
return tile;

Code:

OpenCv环境搭建移步此文章

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.io.IOException;

public class FindTileCoordinates {

static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}

/**
* 在目标图片中寻找模板图片
*
* @param input_path 输入
* @param template_path 模板
* @return
*/
public double[] searchFor(String input_path, String template_path) {
Mat m_input = Imgcodecs.imread(input_path);
Mat m_template = Imgcodecs.imread(template_path);

int result_rows = m_input.rows() - m_template.rows() + 1;
int result_cols = m_input.cols() - m_template.cols() + 1;
Mat g_result = new Mat(result_rows, result_cols, CvType.CV_32FC1);

Imgproc.matchTemplate(m_input, m_template, g_result, Imgproc.TM_CCORR_NORMED);

Core.normalize(g_result, g_result, 0, 1, Core.NORM_MINMAX, -1, new Mat());
Core.MinMaxLocResult mmlr = Core.minMaxLoc(g_result);
Point matchLocation = mmlr.maxLoc;

double x = matchLocation.x + (m_template.cols() / 2);
double y = matchLocation.y + (m_template.rows() / 2);
double[] tile = {x, y};
return tile;
}


public static void main(String[] args) throws IOException {
double[] doubles = new FindTileCoordinates().searchFor(
"input.png",
"template.png"
);
System.out.println(doubles[0] + "-----" + doubles[1]);
}

}

结果

符合要求


文章到此就结束啦,感谢查阅。