2019-06-01 20:57:00 a58456148 阅读数 15
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4125 人正在学习 去看看 贾志刚

演示用局部图片匹配整张图片

VS2017 + OpenCV4.0.1编译

 1 #include <iostream>
 2 #include <opencv2/opencv.hpp>
 3 #include <opencv2/core.hpp>
 4 #include <opencv2/highgui.hpp>
 5 #include <opencv2/imgproc.hpp>
 6 using namespace std;
 7 using namespace cv;
 8 
 9 //定义全局变量
10 Mat src, temp, res;
11 
12 //显示窗口名
13 string img_window = "source image";
14 string res_window = "result image";
15 
16 int match_method;
17 int max_tracker = 5;
18 
19 //滑动条回调函数
20 void match(int pos, void*)
21 {
22     Mat subImg;
23     src.copyTo(subImg);//拷贝副本
24     int res_row = src.rows - temp.rows + 1;
25     int res_col = src.cols - temp.cols + 1;
26     res.create(res_row, res_col, CV_32FC1);//创建结果矩阵
27 
28     //模板匹配
29     matchTemplate(subImg, temp, res, match_method);
30     normalize(res, res, 0, 1, NORM_MINMAX, -1, Mat());
31 
32     //定位
33     double minVal, maxVal;
34     Point minLoc, maxLoc, matchLoc;
35     minMaxLoc(res, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
36 
37     //分类讨论
38     if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED)
39         matchLoc = minLoc;
40     else
41         matchLoc = maxLoc;
42 
43     //矩形框显示匹配结果
44     rectangle(subImg, matchLoc, Point(matchLoc.x + temp.cols, matchLoc.y + temp.rows), Scalar(0, 255, 0), 2);
45     rectangle(res, matchLoc, Point(matchLoc.x + temp.cols, matchLoc.y + temp.rows), Scalar(0, 255, 0), 2);
46     
47     imshow(img_window, subImg);
48     imshow(res_window, res);
49 }
50 
51 int main()
52 {
53     //读入原图和模板图
54     src = imread("D:\\trashBox\\testIMG\\memory.jpg");
55     temp = imread("D:\\trashBox\\testIMG\\temp.png");
56     imshow("模板", temp);
57     
58     //创建显示窗口
59     namedWindow(img_window);
60     namedWindow(res_window);
61 
62     //创建滑动条
63     match(2, 0);
64     createTrackbar("匹配方法", img_window, &match_method, max_tracker, match);
65     
66     waitKey(0);
67     return 0;
68 }

参考资料

【1】http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/histograms/template_matching/template_matching.html#template-matching

转载于:https://www.cnblogs.com/yocichen/p/10960967.html

2019-07-14 00:47:46 qq_34814092 阅读数 767
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4125 人正在学习 去看看 贾志刚

Java OpenCV-4.0.0 图像处理22 图像模板匹配

Java OpenCV-4.0.0 图像处理 图像模板匹配

模板匹配就是在整个图像区域发现与给定子图像匹配的小块区域。

package comxu.opencv.image;

import org.opencv.core.Core;
import org.opencv.core.Core.MinMaxLocResult;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;


/**  
 * 
 * @Title: Image.java   
 * @Package com.xu.opencv   
 * @Description: TODO   
 * @author: xuhyacinth     
 * @date: 2019年7月13日 下午12:10:14   
 * @version: V-1.0 
 * @Copyright: 2019 xuhyacinth
 *
 */
public class Image {

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


	public static void main(String[] args) {
		templete(Imgproc.TM_SQDIFF_NORMED);
	}

	/**
	 * OpenCV-4.1.0 模板匹配
	 * <table border="1" cellpadding="8"> 
	 * <tr><th>输入参数</th><th>参数解释</th></tr> 
	 * <tr><td align="left">TM_SQDIFF是平方差匹配、TM_SQDIFF_NORMED是标准平方差匹配</td><td>利用平方差来进行匹配,最好匹配为0.匹配越差,匹配值越大。</td></tr> 
	 * <tr><td align="left">TM_CCORR是相关性匹配、TM_CCORR_NORMED是标准相关性匹配</td><td>采用模板和图像间的乘法操作,数越大表示匹配程度较高, 0表示最坏的匹配效果。</td></tr> 
	 * <tr><td align="left">TM_CCOEFF是相关性系数匹配、TM_CCOEFF_NORMED是标准相关性系数匹配</td><td>将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列)。</td></tr> 
	 * <tr><td colspan="2">随着从简单的测量(平方差)到更复杂的测量(相关系数),我们可获得越来越准确的匹配(同时也意味着越来越大的计算代价)。</td></tr> 
	 * <tr><td colspan="2">相关性是越接近1越大越好,平方差是越小越好,所以TM_SQDIFF在使用时和其他的是有所区别的。</td></tr> 
	 * <tr><td colspan="2">模板匹配结果Mat要是32位的。</td></tr> 
	 * </table>
	 * @return: void  
	 * @date: 2019年5月7日12:16:55
	 */
	public static void templete(int method) {
		// 1 获取待匹配图片
		Mat templete=Imgcodecs.imread("C:\\Users\\hyacinth\\Pictures\\Camera Roll\\templete01.jpg");
		// 2 获取匹配模板
		Mat demo=Imgcodecs.imread("C:\\Users\\hyacinth\\Pictures\\Camera Roll\\templete02.jpg");

		int width=templete.cols()-demo.cols()+1;
		int height=templete.rows()-demo.rows()+1;
		// 3 创建32位模板匹配结果Mat
		Mat result=new Mat(width,height,CvType.CV_32FC1);
		// 4 调用 模板匹配函数
		Imgproc.matchTemplate(templete, demo, result, method);
		// 5 归一化
		Core.normalize(result, result,0, 1, Core.NORM_MINMAX, -1, new Mat());  
		// 6 获取模板匹配结果
		MinMaxLocResult mmr = Core.minMaxLoc(result);
		// 7 绘制匹配到的结果
		double x,y;
		if (method==Imgproc.TM_SQDIFF_NORMED || method==Imgproc.TM_SQDIFF) {
			x = mmr.minLoc.x;
			y = mmr.minLoc.y;
		} else {
			x = mmr.maxLoc.x;
			y = mmr.maxLoc.y;
		}
		Imgproc.rectangle(templete,new Point(x,y),new Point(x+demo.cols(),y+demo.rows()),new Scalar( 0, 0, 255),2,Imgproc.LINE_AA);
		Imgproc.putText(templete,"Match Success",new Point(x,y),Imgproc.FONT_HERSHEY_SCRIPT_COMPLEX, 1.0, new Scalar(0, 255, 0),1,Imgproc.LINE_AA);
		// 8 显示结果
		HighGui.imshow("模板匹配", templete);
		HighGui.waitKey(0);

	}

}

模板匹配

2019-01-20 17:04:18 qq_42887760 阅读数 192
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4125 人正在学习 去看看 贾志刚

模板匹配介绍

我们需要2幅图像:

  • 原图像 (I): 在这幅图像里,我们希望找到一块和模板匹配的区域
  • 模板 (T): 将和原图像比照的图像块
    在这里插入图片描述
  • 模板匹配就是在整个图像区域发现与给定子图像匹配的小块区域。
  • 所以模板匹配首先需要一个模板图像T(给定的子图像)
  • 另外需要一个待检测的图像-源图像S
  • 工作方法,在带检测图像上,从左到右,从上向下计算模板图像与重叠子图像的匹配度,匹配程度越大,两者相同的可能性越大。

模板匹配原理

  • 我们的目标是检测最匹配模板的原图像的区域:
    在这里插入图片描述
  • 为了确定匹配模板区域, 我们不得不滑动模板图像和原图像进行比较 :
    在这里插入图片描述
  • 对于 模板(T) 覆盖在 原图像 (I) 上的每个位置,你把度量值保存 到 结果图像矩阵 ( R ) 中. 在 R 中的每个位置 (x,y) 都包含匹配度量值:
    在这里插入图片描述
  • 上图(右)就是 TM_CCORR_NORMED 方法处理后的结果图像 R . 最白的位置代表最高的匹配. 正如您所见, 黑色框住的位置很可能是结果图像矩阵中的最大数值, 所以这个区域 (以这个点为顶点,长宽和模板图像一样大小的矩阵) 被认为是匹配的.
  • 实际上, 我们使用函数 minMaxLoc 来定位在矩阵 R 中的最大值点 (或者最小值, 根据函数输入的匹配参数) .

void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, InputArray mask=noArray())
src:输入图像。
minVal:在矩阵 src中存储的最小值,可输入NULL表示不需要。
maxVal :在矩阵 src中存储的最大值,可输入NULL表示不需要。
minLoc:在结果矩阵中最小值的坐标,可输入NULL表示不需要,Point类型。
maxLoc:在结果矩阵中最大值的坐标,可输入NULL表示不需要,Point类型。
mask:可选的掩模

模板匹配介绍 – 匹配算法介绍

OpenCV中提供了六种常见的匹配算法如下:

  • 计算平方不同 : 计算出来的值越小,越相关 TM_SQDIFF = 0
    在这里插入图片描述
  • 计算相关性: 计算出来的值越大,越相关 TM_CCORR = 2
    在这里插入图片描述
  • 计算相关系数: 计算出来的值越大,越相关 TM_CCOEFF = 4
    在这里插入图片描述
  • 计算归一化平方不同 : 计算出来的值越接近0,越相关 TM_SQDIFF_NORMED = 1
    在这里插入图片描述
  • 计算归一化相关性: 计算出来的值越接近1,越相关 TM_CCORR_NORMED = 3
    在这里插入图片描述
  • 计算归一化相关系数: 计算出来的值越接近1,越相关 TM_CCOEFF_NORMED = 5
    在这里插入图片描述

在这里插入图片描述

相关API介绍cv::matchTemplate

matchTemplate(
InputArray image,// 源图像,必须是8-bit或者32-bit浮点数图像
InputArray templ,// 模板图像,类型与输入图像一致
OutputArray result,// 输出结果,必须是单通道32位浮点数,假设源图像WxH,模板图像wxh, 则结果必须为W-w+1, H-h+1的大小。
int method,//使用的匹配方法
InputArray mask=noArray()//(optional)
)

在这里插入图片描述

程序代码

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
 
// 定义一些全局变量, 例如原图像(img), 模板图像(templ) 和结果图像(result) , 
// 还有匹配方法以及窗口名称:
Mat img, templ, result;
char* image_window = "Source Image";
char* result_window = "Result window";
 
int match_method = TM_SQDIFF;
int max_Trackbar = 5;

void MatchingMethod( int, void* );
 
int main( int argc, char** argv )
{
	// 1. 载入原图像和模板块
	img = imread("E:/Experiment/OpenCV/Pictures/TargetSearch.jpg");
	templ = imread("E:/Experiment/OpenCV/Pictures/Target.jpg");
	imshow("模板图像",templ);
 
	// 创建窗口
	namedWindow( image_window, CV_WINDOW_AUTOSIZE );
	namedWindow( result_window, CV_WINDOW_AUTOSIZE );
 
	// 2. 创建滑动条并输入将被使用的匹配方法. 一旦滑动条发生改变,回调函数 MatchingMethod 就会被调用.
	char* trackbar_label = "模板匹配方式";
	createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod );
 
	MatchingMethod( 0, 0 );
 
	waitKey(0);
	return 0;
}

void MatchingMethod( int, void* )
{
	// 将被显示的原图像
	Mat img_display;
	img.copyTo( img_display );
 
	// 创建输出结果的矩阵
	int result_cols =  img.cols - templ.cols + 1;
	int result_rows = img.rows - templ.rows + 1;
	// 创建了一幅用来存放匹配结果的输出图像矩阵. 仔细看看输出矩阵的大小(它包含了所有可能的匹配位置)
	result.create( result_cols, result_rows, CV_32FC1 );
 
	// 执行模板匹配操作,并对结果进行归一化:
	matchTemplate( img, templ, result, match_method );
	normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
 
	// 通过函数 minMaxLoc 定位最匹配的位置
	double minVal, maxVal; 
	Point minLoc, maxLoc;
	Point matchLoc;
	
	//通过使用函数 minMaxLoc ,我们确定结果矩阵 R 的最大值和最小值的位置.
	minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );//寻找result中最大值,最小值,及它们所在的位置
 
	// 对于方法 SQDIFF 和 SQDIFF_NORMED, 越小的数值代表更高的匹配结果. 而对于其他方法, 数值越大匹配越好
	if( match_method  == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED ){ 
		matchLoc = minLoc; 
	}else{ 
		matchLoc = maxLoc; 
	}
 
	// 绘制矩形
	rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
	rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
 
	imshow( image_window, img_display );
	imshow( result_window, result );
 
	return;
}


运行结果

在这里插入图片描述
在这里插入图片描述

参考博客

  1. https://blog.csdn.net/LYKymy/article/details/83210432 (我觉得他写的比我好,推荐阅读)
  2. https://blog.csdn.net/huanghuangjin/article/details/81180568
2019-12-10 15:17:17 weixin_43585712 阅读数 7
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4125 人正在学习 去看看 贾志刚

模板匹配

模板匹配顾名思义就是给定一幅影像(模板)然后在另一幅 图像中寻找这个模板的操作。它是一种用来在一幅大图中 寻找模板图像位置的方法。在OpenCV中有cv2.matchTemplate() 函数供我们方便调用。它的工作原理与2D卷积函数一样, 将模板图像在输入图像(大图)上滑动,并且在每一个位置对 模板图像和与其对应的输入图像的子区域进行比较。返回 的结果是一个灰度图像,每一个像素值表示了此区域与模板 的匹配程度。

匹配步骤

1.输入原图像(I)和模板图像(T)。在原图像中我们希望找到一块和模板匹配的区域
2.通过将模板在原图像上滑动来寻找最匹配的区域。 这里所谓的滑动是指模板图像块一次移动一个像素(从左往右,从上往下)。 在每一个位置,都进行一次度量计算,来判断该像素对应的原图像的特定区域 与模板图像的相似度。
3.对于模板T覆盖在I上的每个位置,把上一步计算的度量值保存在结果图像矩阵R中。 在R中每个位置都包含对应的匹配度量值。
4.在结果图像矩阵中寻找最值(最大或最小,根据算法不同而不同)。最值所对应的像素的位置即认为是最高的匹配。 以该点为顶点,长宽和模板大小图像一样的矩阵认为是匹配区域。在OpenCV中可以用cv2.minMaxLoc()函数获得最值坐标。

匹配算法

上面说了模板匹配的核心步骤。可以发现在步骤中有个核心问题。 那就是如何度量匹配程度,如何进行度量计算。在OpenCV中提供了 6中不同方法。这里就以这6种算法为基础介绍匹配算法。在下列公式中, T(x,y)表示模板,I(x,y)表示原图像,R(x,y)表示模板与原图相似度函数。 x、y表示某个像素,x’、y’表示循环变量,在模板那么大的范围内进行循环。
下面给出两个算法公式:
在这里插入图片描述

Opencv实现

如果输入图像大小是(W × H),模板大小是(w × h),输出结果大小就是(W-w+1, H-h+1)。 当得到这幅图之后,就可以使用函数cv2.minMaxLoc()来找到其中最小值和最大值位置了。 第一个值为矩形左上角的点(位置),(w,h)为模板矩形的宽和高。这个矩形就是找到的模板区域了。 下面是实例代码:

单个对象匹配


import numpy as np
import cv2
from matplotlib import pyplot as plt
# 依次读取原图与模板
plt.rcParams["font.family"] = "SimHei"#直接修改配置字典,设置默认字体
img = cv2.imread("E:/ruanjianDM/jupyternoerbookDM/Opencv3/data/apple.png")
template = img [100:200,0:100,:]
plt.subplot(131),plt.imshow(template[:,:,::-1])
plt.axis("off"),plt.title("模板图像")
#依次获取模板的宽高,用于后续绘制矩形
h = template.shape[0]
w = template.shape[1]
"#调用匹配函数"
# 第一个参数是原图
# 第二个参数是模板
# 第三个参数是匹配算法
# 返回的结果是一个二维的float类型的数组,大小为W-w+1 * H-h+1
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF)

# 获取返回结果中最值及其在res中的位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

# 构造矩形并在原图上绘制
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(img, top_left, bottom_right, (255, 255, 0), 5)

# 在使用Matplotlib显示之前,需要调整BGR的顺序
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
img = cv2.merge((r, g, b))

# 打印相关信息
"可以观察到图像,模板,R矩阵的大小符合公式"
print (img.shape,template.shape,res.shape,res.dtype,cv2.minMaxLoc(res))

# 利用Matplotlib绘图对比
plt.subplot(132), plt.imshow(img)
plt.axis("off"),plt.title("原图")
plt.subplot(133), plt.imshow(res, cmap='gray')
#匹配矩阵R的信息,最亮的点认为最匹配的点
plt.axis("off"),plt.title("R图像")
plt.show()

在这里插入图片描述

多个图像匹配

在上面的例子中,原图中只出现了一次模板中的对象,但有时更有可能一幅图像中出现多个模板对象,这时就需要多对象匹配了。 在OpenCV中cv2.minMaxLoc()只会返回最值的位置。所以显然现在不能使用这个函数了。我们需要设置一个阈值,当R值大于这个 阈值时,认为是模板对象,否则不是。所以这里显然用标准化的方法更加合适,否则我们无法确定阈值。代码如下:

import cv2
from matplotlib import pyplot as plt
import numpy as np

# 依次读取原图与模板
img = cv2.imread("E:/ruanjianDM/jupyternoerbookDM/Opencv3/data/house.jpg")
template = cv2.imread("E:/ruanjianDM/jupyternoerbookDM/Opencv3/data/house1.jpg")

# 依次获取模板的宽高,用于后续绘制矩形
h = template.shape[0]
w = template.shape[1]

"调用匹配函数"
# 第一个参数是原图
# 第二个参数是模板
# 第三个参数是匹配算法
# 返回的结果是一个二维的float类型的数组,大小为W-w+1 * H-h+1
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)

# 设定阈值
threshold = 0.8

# 从res中提取大于阈值的像素的位置
loc = np.where(res >= threshold)

# 遍历不同位置,绘制矩形
# 在函数调用中使用*list/tuple,表示将list/tuple分开,作为位置参数传递给对应函数(前提是对应函数支持不定个数的位置参数)
# 切片[::-1]是将列表或字符倒过来
for pt in zip(*loc[::-1]):
    cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)

# 在使用Matplotlib显示之前,需要调整BGR的顺序
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
img = cv2.merge((r, g, b))

# 利用Matplotlib绘图对比
plt.subplot(121), plt.imshow(res, cmap='gray')
plt.subplot(122), plt.imshow(img, cmap='gray')
plt.show()

左图是R图像,右图是匹配图像
在这里插入图片描述

2015-10-02 00:48:06 jia20003 阅读数 22348
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4125 人正在学习 去看看 贾志刚

一:基本原理

NCC是一种基于统计学计算两组样本数据相关性的算法,其取值范围为[-1, 1]之间,而对图像来说,每个像素点都可以看出是RGB数值,这样整幅图像就可以看成是一个样本数据的集合,如果它有一个子集与另外一个样本数据相互匹配则它的ncc值为1,表示相关性很高,如果是-1则表示完全不相关,基于这个原理,实现图像基于模板匹配识别算法,其中第一步就是要归一化数据,数学公式如下:


二:实现步骤

(1)      获取模板像素并计算均值与标准方差、像素与均值diff数据样本

(2)      根据模板大小,在目标图像上从左到右,从上到下移动窗口,计

算每移动一个像素之后窗口内像素与模板像素的ncc值,与阈值比较,大于

阈值则记录位置

(3)      根据得到位置信息,使用红色矩形标记出模板匹配识别结果。

(4)      UI显示结果

 

三:编程实现

基于JAVA语言完成了整个算法编程实现与演示,其中第一步的代码如下:

		int tw = template.getWidth();
		int th = template.getHeight();
		int[] tpixels = new int[tw * th];
		getRGB(template, 0, 0, tw, th, tpixels);
		for(int i=0; i<tpixels.length; i++)
		{
			tpixels[i] = (tpixels[i] >> 16) & 0xff;
		}
		double[] meansdev = getPixelsMeansAndDev(tpixels);
		double[] tDiff = calculateDiff(tpixels, meansdev[0]);
		int raidus_width = tw / 2;
		int raidus_height = th / 2;
第二步的实现代码如下:

		int[] windowPixels = new int[tw * th];
		Arrays.fill(windowPixels, 0);
		for (int row = 0; row < height; row++) {
			for (int col = 0; col < width; col++) {
				// calculate the means and dev for each window
				if(row <  raidus_height || (row + raidus_height) >= height)
					continue;
				if(col < raidus_width || (col + raidus_width) >= width) 
					continue;
				int wrow = 0;
				Arrays.fill(windowPixels, 0);
				for(int subrow = -raidus_height; subrow <= raidus_height; subrow++ )
				{
					int wcol = 0;
					for(int subcol = -raidus_width; subcol <= raidus_width; subcol++ )
					{
						if(wrow >= th || wcol >= tw)
						{
							continue;
						}
						windowPixels[wrow * tw + wcol] = getPixelValue(width, col + subcol, row + subrow, inPixels);
						wcol++;
					}
					wrow++;
				}
				// calculate the ncc
				double[] _meansDev = getPixelsMeansAndDev(windowPixels);
				double[] diff = calculateDiff(windowPixels, _meansDev[0]);
				double ncc = calculateNcc(tDiff, diff, _meansDev[1], meansdev[1]);
				if(ncc > threhold) {
					Point mpoint = new Point();
					mpoint.x = col;
					mpoint.y  = row;
					points.add(mpoint);
				}
			}
		}
第三步的实现代码如下:

		// draw matched template on target image according position
		setRGB( dest, 0, 0, width, height, inPixels );
		Graphics2D g2d = dest.createGraphics();
		g2d.setPaint(Color.RED);
		g2d.setStroke(new BasicStroke(4));
		for(Point p : points)
		{
			g2d.drawRect(p.x - raidus_width, p.y - raidus_height, tw, th);
		}
其中第二步用到的计算NCC的方法实现如下:

	private double calculateNcc(double[] tDiff, double[] diff, double dev1, double dev2) {
		// TODO Auto-generated method stub
		double sum = 0.0d;
		double count = diff.length;
		for(int i=0; i<diff.length; i++)
		{
			sum += ((tDiff[i] * diff[i])/(dev1 * dev2));
		}
		return (sum / count);
	}
UI部分完整源代码如下:

package com.gloomyfish.image.templae.match;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class DemoUI extends JComponent {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private BufferedImage targetImage;
	private BufferedImage template;
	
	public DemoUI()
	{
		super();
		java.net.URL imageURL = this.getClass().getResource("words.png");
		java.net.URL templateURL = this.getClass().getResource("template.png");
		
		try {
			template = ImageIO.read(templateURL);
			targetImage = ImageIO.read(imageURL);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void setTarget(BufferedImage target) {
		this.targetImage = target;
	}

	@Override
	protected void paintComponent(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		if(targetImage != null) {
			g2.drawImage(targetImage, 10, 10, targetImage.getWidth(), targetImage.getHeight(), null);
		}
		if(template != null) {
			g2.drawImage(template, 20+targetImage.getWidth(), 10, template.getWidth(), template.getHeight(), null);
		}
	}
	
	public static void main(String[] args) {
		JFrame f = new JFrame("模板匹配与识别");
		JButton okBtn = new JButton("匹配");
		final DemoUI ui = new DemoUI();
		okBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				
				ui.process();
			}
		});
		
		JPanel btnPanel = new JPanel();
		btnPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
		btnPanel.add(okBtn);
		
		f.getContentPane().add(btnPanel, BorderLayout.SOUTH);
		f.getContentPane().add(ui, BorderLayout.CENTER);
		f.setSize(500, 500);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setVisible(true);
	}

	protected void process() {
		NccTemplateMatchAlg algo = new NccTemplateMatchAlg(template);
		targetImage = algo.filter(targetImage, null);
		this.repaint();
	}

}
四:程序运行效果如下


其中左边是目标图像、右边为模板图像

PS:博客从10月份开始每月都有多篇相关图像处理文章更新

欢迎大家继续关注


模板匹配算法

阅读数 20557

模板匹配(Template Matching)算法

博文 来自: zhi_neng_zhi_fu
没有更多推荐了,返回首页