Python OpenCV 365 天学习计划,与橡皮擦一起进入图像领域吧。
基础知识铺垫
今天的 1 个小时,我们要交给模板匹配了,而且学习起来比较轻松,因为我看到一句话,模板匹配是最没用的匹配方式,应用场景很少。
就喜欢这样的技术,学起来的摩擦力小,不容易掉头发。
模板匹配
模板匹配大意就是在整个图像区域寻找已有的小图像,在寻找之前,你需要准备一个待寻找的图像,以及一个小图
寻找的形式是从左到右,从上到下,这个找法很形象了,一行一行的找。
在寻找的过程中,通过 OpenCV 封装好的算法,计算小图与大图的匹配度,这个匹配度越大,两张图片相同的可能性越大。
模板匹配函数原型
在 Python 中,通过 help 函数,可以查看任意函数的说明。
matchTemplate( image, templ, method[ , result[ , mask] ] ) - > result
参数说明如下:
image :待检索的图像;
templ :小图,要求不大于待搜索图像;
method :匹配方法,下表提供,算法不需要掌握,知道用法即可;
result :结果图像;
mask :掩膜,需要与 templ 有相同的数据类型和大小,默认不设置,仅支持 method 参数值为 TM_SQDIFF 和 TM_CCORR_NORMED
关于 method 参数的值有以下几种情况:
TM_SQDIFF :平方差匹配;
TM_SQDIFF_NORMED :标准平方差匹配,利用平方差来进行匹配,最好匹配为 0,匹配越差,匹配值越大;
TM_CCORR :相关性匹配;
TM_CCORR_NORMED :标准相关性匹配,采用模板和图像间的乘法操作,数越大表示匹配程度较高, 0 表示最坏的匹配效果;
TM_CCOEFF :相关性系数匹配;
TM_CCOEFF_NORMED :标准相关性系数匹配,将模版对其均值的相对值与图像对其均值的相关值进行匹配,1 表示完美匹配,-1 表示糟糕的匹配,0 表示没有任何相关性(随机序列)。
以上内容整理自网络
接下来编写测试代码:
import cv2 as cv
target = cv. imread( "./target.jpg" )
template = cv. imread( "./template.jpg" )
th, tw = template. shape[ : 2 ]
result = cv. matchTemplate( target, template, cv. TM_SQDIFF_NORMED)
print ( type ( result) )
cv. imshow( "image" , result)
cv. waitKey( )
注意下图中,最终匹配到的区域颜色最深。 下面我们将其标记出来,需要用到一个新的函数,具体如下。
minMaxLoc 函数
该函数是在给定的矩阵中寻找最大值和最小值,并给出它们的位置。
特别说明是如果需要在所有的通道中查找最小或者最大元素,要先将矩阵重新解释为单通道,好吧,引出归一化的概念了。
那我们先把这个函数学到收,之后在把归一化的函数补充上。
函数原型如下:
minMaxLoc( src[ , mask] ) - > minVal, maxVal, minLoc, maxLoc
原型比较简单,输入一个图像之后,可以返回 4 个值。
这 4 个值分别是,最大值,最小值以及最大值与最小值的位置。
上文我们使用的是 cv.TM_SQDIFF_NORMED 方法,按照上面的叙述,匹配值最小越好,所以需要获取一下图像的最小值位置。
修改上文代码如下:
import cv2 as cv
target = cv. imread( "./target.jpg" )
template = cv. imread( "./template.jpg" )
th, tw = template. shape[ : 2 ]
result = cv. matchTemplate( target, template, cv. TM_SQDIFF_NORMED)
min_val, max_val, min_loc, max_loc = cv. minMaxLoc( result)
tl = min_loc
print ( tl)
br = ( tl[ 0 ] + tw, tl[ 1 ] + th)
cv. rectangle( target, tl, br, ( 0 , 0 , 255 ) , 2 )
cv. imshow( "image" , target)
cv. waitKey( )
最终运行效果如下,匹配成功。 其他的 method 你自行测试吧。
补一个 cv2.normalize
学习新的函数,先把概念通读,尝试理解,理解不要在降格到应用。
归一化就是把待处理的数据进行处理,这里的处理就是某种算法了,然后将数据限制在一个范围内(范围由我们自己定义)
归一化之后,数据会变得更加有可比性,具体原因还未找到可靠资料。
函数原型如下:
dst = cv2. normalize( src[ , dst[ , alpha[ , beta[ , norm_type[ , dtype[ , mask] ] ] ] ] ] )
参数说明:
src :输入数组;
dst :与 src 大小相同的输出数组;
alpha :如果 norm_type 为 NORM_MINMAX ,则 alpha 为最小值或最大值,如果 norm_type 为其他类型,则为归一化要乘的系数;
beta :如果 norm_type 为 NORM_MINMAX ,则 beta 为最小值或最大值,如果 norm_type 为其他类型,beta 被忽略,此处不会被用到,一般传入 0;
norm_type :归一化类型,常见的有 NORM_L1, NORM_L2, NORM_INF, NORM_MINMAX;
dtype :如果取负值时,dst 与 src 同样的类型,否则,dst 和 src 有同样的通道数,且此时图像深度为 CV_MAT_DEPTH(dtype);
mask :掩膜。
应用起来比较简单,例如本篇博客中的案例,只需要增加如下代码即可。
cv. normalize( result, result, 0 , 1 , cv. NORM_MINMAX, - 1 )
橡皮擦的小节
希望今天的 1 个小时,你有所收获,我们下篇博客见~
相关阅读
技术专栏
Python 爬虫 100 例教程,超棒的爬虫教程,立即订阅吧
Python 爬虫小课,精彩 9 讲
逗趣程序员
曝光,程序员的 10 个摸鱼神器
5 个无聊 Python 程序,用 Python 整蛊你的朋友们吧
10 年老程序员教你甩锅必杀技,论【如何优雅的甩锅】
你想被开除吗?来看看程序员【离职小技巧】吧
今天是持续写作的第 70 / 100 天。 如果你有想要交流的想法、技术,欢迎在评论区留言。
如果你想跟博主建立亲密关系,可以关注博主,或者关注博主公众号 “非本科程序员”,了解一个非本科程序员是如何成长的。 博主 ID:梦想橡皮擦,希望大家点赞、评论、收藏
本文同步分享在 博客“梦想橡皮擦”(CSDN)。 如有侵权,请联系 support@oschina.cn 删除。 本文参与“OSC源创计划 ”,欢迎正在阅读的你也加入,一起分享。