OpenCV图像处理笔记[08]
[实验]模板匹配
-
模板匹配就是在整个图像区域发现与给定子图像匹配的小块区域。
-
所以模板匹配首先需要一个模板图像T(给定的子图像)
-
另外需要一个待检测的图像-源图像S
-
工作方法,在带检测图像上,从左到右,从上向下计算模板图像与重叠子图像的匹配度程度越大,两者相同的可能性越大
T-灰度变换-二值化-轮廓-外接矩形 信用卡-灰度-二值化-顶帽-梯度-闭操作-闭操作-轮廓-二值化-切分 模板匹配
- imutils : 工具包
imutils提供一系列便捷功能进行基本的图像处理功能,如平移,旋转,缩放,骨架,matplotlib图像显示,排序的轮廓,边缘检测
-
argparse : 命令行参数解析包
1. 创建一个解析器
使用
argparse
的第一步是创建一个ArgumentParser
对象:
>>> parser = argparse.ArgumentParser(description='Process some integers.')
2. 添加参数
给一个
ArgumentParser
添加程序参数信息是通过调用add_argument()
方法完成的。通常,这些调用指定ArgumentParser
如何获取命令行字符串并将其转换为对象。这些信息在parse_args()
调用时被存储和使用
3. 解析参数
ArgumentParser
通过 parse_args()
方法解析参数。它将检查命令行,把每个参数转换为适当的类型然后调用相应的操作。在大多数情况下,这意味着一个简单的 Namespace
对象将从命令行参数中解析出的属性构建:
>>> parser.parse_args(['--sum', '7', '-1', '42']) Namespace(accumulate=<built-in function sum>, integers=[7, -1, 42])
在脚本中,通常 parse_args()
会被不带参数调用,而 ArgumentParser
将自动从 sys.argv
中确定命令行参数。
# 根据坐标提取每一个组 group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5] cv_show('group',group)
其中“+5”,"-5"是为了不把特征值丢掉
- cv2.findContours()函数
# 计算轮廓 #cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标 #返回的list中每个元素都是图像中的一个轮廓 ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img,refCnts,-1,(0,0,255),3) cv_show('img',img) print (np.array(refCnts).shape) refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] #排序,从左到右,从上到下 digits = {}
- cv2.findContours()
image, contours, hierarchy=cv2.findContours(image,mode,method)
-
参数
- mage ,修改后的原始图像
- contours , 轮廓
- hierarchy , 图像的拓扑信息(轮廓层次)
- image , 原始图像
- mode , 轮廓检索模式
- method , 轮廓的近似方法
-
cv2.drawContours( )
r=cv2.drawContours(),contours,contourldx,color[,thickness])
- r : 目标图像,直接修改目标的像素点,实现绘制。
- o : 原始图像
- contours : 需要绘制的边缘数组。
- contourldx : 需要绘制的边缘索引,如果全部绘制则为一1。
- color : 绘制的颜色,为BGR格式的Scalar。
- thickness : 可选,绘制的密度,即描绘轮廓时所用的画笔粗细。
-
refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0]
def sort_contours(cnts, method="left-to-right"): reverse = False i = 0 if method == "right-to-left" or method == "bottom-to-top": reverse = True if method == "top-to-bottom" or method == "bottom-to-top": i = 1 boundingBoxes = [cv2.boundingRect(c) for c in cnts] #用一个最小的矩形,把找到的形状包起来x,y,h,w (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes), key=lambda b: b[1][i], reverse=reverse)) return cnts, boundingBoxes
for (i, c) in enumerate(refCnts): # 计算外接矩形并且resize成合适大小 (x, y, w, h) = cv2.boundingRect(c) roi = ref[y:y + h, x:x + w] roi = cv2.resize(roi, (57, 88)) # 每一个数字对应每一个模板 digits[i] = roi
enumerate
:
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
enumerate(sequence, [start=0])
参数
- sequence -- 一个序列、迭代器或其他支持迭代对象。
- start -- 下标起始位置。
返回值
返回 enumerate(枚举) 对象。
cv2.boundingRect(img)
得到包覆此轮廓的最小正矩形
- cv2.getStructuringElement( )
# 初始化卷积核读入信用卡图像 rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))#根据字体大小设定核的大小 sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
返回指定形状和尺寸的结构元素。
例: kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(11,11))
函数的第一个参数表示内核的形状,有三种形状可以选择。
矩形:MORPH_RECT;
交叉形:MORPH_CROSS;
椭圆形:MORPH_ELLIPSE;
第二和第三个参数分别是内核的尺寸以及锚点的位置。一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得
getStructuringElement函数的返回值: 对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心点。element形状唯一依赖锚点位置,其他情况下,锚点只是影响了形态学运算结果的偏移。
#礼帽操作,突出更明亮的区域 tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel) #明亮的区域提取出来 cv_show('tophat',tophat) # 梯度运算 gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, #ksize=-1相当于用3*3的 ksize=-1)
礼帽(image) = 原始图像(image) - 开运算(image)
-
得到噪声图像
函数morphologyEX
result = cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
-
result ,礼帽结果 | img,源图像
| cv2.MORPH_TOPHAT,礼帽
| kernel,卷积核 例:kernel = np.ones((5,5),np.unit8)
dst = cv2.Sobel( src, ddepth, dx, dy, [ ksize ])
dst, 计算结果 src, 原始图像
ddepth, 处理结果图像深度
dx, x轴方向
dy, y轴方向
ksize, 核大小
#通过闭操作(先膨胀,再腐蚀,去除内部空洞)将数字连在一起 gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel) cv_show('gradX',gradX) #THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0 thresh = cv2.threshold(gradX, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] cv_show('thresh',thresh)
闭运算(image) = 腐蚀(膨胀(image))
先膨胀,后腐蚀
它有助于关闭前景物体内部的小孔,或物体上的小黑点
函数morphologyEX
closing = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)
closing ,闭运算结果 | img,源图像
| cv2.MORPH_CLOSE,闭运算
| kernel,卷积核 例:kernel = np.ones((5,5),np.unit8)
opencv二值化函数 threshold(src_gray,dst,threshold_value,max_BINARY_value,threshold_type),threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU)
这里二值化,即图像像素值变成0或255,THRESH_OTSU是确定阈值分割点,这个是库函数确定的
Ostu方法又名最大类间差方法,通过统计整个图像的直方图特性来实现全局阈值T的自动选取
算法步骤:
先计算图像的直方图,即将图像所有的像素点按照0~255共256个bin,统计落在每个bin的像素点数量
归一化直方图,也即将每个bin中像素点数量除以总的像素点
i表示分类的阈值,也即一个灰度级,从0开始迭代
通过归一化的直方图,统计0~i 灰度级的像素(假设像素值在此范围的像素叫做前景像素) 所占整幅图像的比例w0,并统计前景像素的平均灰度u0;统计i~255灰度级的像素(假设像素值在此范围的像素叫做背景像素) 所占整幅图像的比例w1,并统计背景像素的平均灰度u1;
计算前景像素和背景像素的方差 g = w0w1(u0-u1) (u0-u1)
i++;转到4),直到i为256时结束迭代
7)将最大g相应的i值作为图像的全局阈值
- 模板匹配函数:
# 在模板中计算每一个得分 for (digit, digitROI) in digits.items(): # 模板匹配 result = cv2.matchTemplate(roi, digitROI,cv2.TM_CCOEFF) (_, score, _, _) = cv2.minMaxLoc(result) scores.append(score)
matchTemplate(InputArray image, InputArray templ, OutputArray result, int method);
image:输入一个待匹配的图像,支持8U或者32F。 templ:输入一个模板图像,与image相同类型。 result:输出保存结果的矩阵,32F类型。 method:要使用的数据比较方法。
result:
result是一个结果矩阵,假设待匹配图像为 I,宽高为(W,H),模板图像为 T,宽高为(w,h)。那么result的大小就为(W-w+1,H-h+1) 。
method:

方差匹配方法:完全匹配会得到1, 完全不匹配会得到0。
归一化方差匹配方法:完全匹配结果为0。
相关性匹配方法:完全匹配会得到很大值,不匹配会得到一个很小值或0。
归一化的互相关匹配方法:完全匹配会得到1, 完全不匹配会得到0。相关系数匹配方法:完全匹配会得到一个很大值,完全不匹配会得到0,完全负相关会得到很大的负数。
归一化的相关系数匹配方法:完全匹配会得到1,完全负相关匹配会得到-1,完全不匹配会得到0。
本文作者:Hecto
本文链接:https://www.cnblogs.com/tow1/p/16546355.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律