使用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; 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); }
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]); }
}
|
结果
符合要求
文章到此就结束啦,感谢查阅。