《OpenCV轻松入门》学习打卡第八天

OpenCV + Python3

  • 第十五章 模板匹配
  • 第十六章 霍夫变换

第十五章 模板匹配

模板匹配是指在当前图像A内寻找与图像B最相似的部分,一般将A称为输入图像,将B称为模板图像。模板匹配的方法是将模板图像B在图像A上滑动,遍历所有像素以完成匹配。
1.模板匹配基础
在OpenCV中,模板匹配是使用函数cv2.matchTemplate()实现的,语法格式为:
result = cv2.matchTemplate(image, templ, method, mask)
其中image为原始图像,必须为8位或者32位的浮点型图像,templ为模板图像,尺寸小于等于原始图像,并且与原始图像具有同样的类型,method为匹配方法,通过TemplateMatchModes实现,有6种可能的值:
· cv2.TM_SQDIFF(0),以方差为依据进行匹配,0则完全匹配
· cv2.TM_SQDIFF_NORMED(1),标准(归一化)平方差匹配
· cv2.TM_CCORR(2),相关匹配
· cv2.TM_CCORR_NORMED(3),标准(归一化)相关匹配
· cv2.TM_CCOEFF(4),相关系数匹配,1表示完美匹配,-1表示糟糕匹配
· cv2.TM_CCOEFF_NORMED(5),标准(归一化)相关系数匹配
mask为模板图像掩模,必须和模板图像templ具有相同的类型和大小,使用默认值即可,返回值result是由每个位置的比较结果组合所构成的一个结果集,类型是单通道32位浮点型,如果输入图像尺寸为WH,模板图像尺寸为wh,则返回值大小为(W-w+1)*(H-h+1),需要注意的是,参数method决定了result的数值,当method为0,1时,result为0表示匹配度最好,值越大,匹配度越差;当method为2,3,4,5时,result的值越小表示匹配度越差,值越大匹配度越好。
从上述分析可以看出,查找方法不同,结果的判定方式也不同。在查找最佳匹配时,首先要确定使用的是何种method,然后再确定到底是查找最大值,还是最小值,查找最值与最值所在的位置,可以使用cv2.minMaxLoc()函数实现,语法格式:
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(src, mask)
综上所述,函数cv2.matchTemplate()返回值中的最值位置就是模板匹配的位置
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(matchTemplate函数的返回值)
通过上述方式,我们确定了模块匹配的矩形对角坐标位置,接下来就可以借助函数cv2.rectangle()将该位置用白色标记出来,语法格式为:
Img = cv2.rectangle(img, pt1, pt2, color, thickness)
参数pt1是矩形的顶点,pt2是pt1的对角顶点,color是要绘制矩形的颜色或灰度级(灰度图像),thickness是矩形边线的宽度。
2.多模板匹配
有些情况下,要搜索的模板图像很可能在输入图像内出现了多次,这时就需要找出多个匹配结果,而函数cv2.minMaxLoc()仅仅能找出最值。无法找出所有匹配位置信息,所有,要匹配多个结果,使用函数cv2.minMaxLoc()是无法实现的,需要利用阈值进行处理
1)获取匹配位置的集合
函数where()能够获取模板匹配位置的集合,对于不同的输入,其返回的值是不同的。
· 当输入(参数)是一维数组时,返回值是一维索引,只有一组索引数组
· 当输入是二维数组时,返回的值是匹配值的位置索引,因此会有两组索引值数组表示返回值的位置
综上所述,函数np.where()可以找出函数cv2.matchTemplate()的返回值中,哪些位置上的值是大于阈值threshold的,在具体实现时,可以采用:
loc = np.where( res >= threshold)
2)循环
要处理多个值,通常要用到循环
3)在循环中使用函数zip()
函数zip()用可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表
4)调整坐标
函数numpy.where()可以获取满足条件的模板匹配位置集合,然后可以使用函数cv2.rectangle()在上述匹配位置绘制矩形来标注匹配位置。但是,函数cv2.rectangle()中用于指定顶点的参数所使用的格式为(列好,行号)的位置索引,所以,在使用函数cv2.rectangle()绘制矩形之前,要先将函数numpy.where()得到的位置索引进行行列互换,使用loc[:, :, -1]即可
5)标记匹配图像的位置
函数cv2.rectangle()可以标记匹配图像的具体位置,分别制定要标记的原始图像,对角顶点,颜色,矩形边线宽度即可。矩形的对角顶点之一可以通过for循环语句从确定的满足条件的“匹配位置集合”内获取

第十六章 霍夫变换

霍夫变换是一种在图像中寻找直线、圆形以及其他简单图形的方法。霍夫变换采用类似于投票的方法来获取当前图像内的形状集合,常见的有圆形、椭圆等。霍夫直线变换用来在图像内寻找直线,霍夫圆变换用来在图像内寻找圆。在OpenCV中,前者可以用函数cv2.HoughLines()和函数cv2.HoughLinesP()实现,后者可以用函数cv2.HoughCircles()实现
1.霍夫直线变换
OpenCV提供了函数cv2.HoughLines()和函数cv2.HoughLinesP()用来实现霍夫直线变换
1)霍夫变换原理
与直角坐标系(对应笛卡尔空间)对应,我们构造一个霍夫坐标系(对应霍夫空间)。在霍夫坐标系中,横坐标采用笛卡尔坐标系中的直线的斜率k,纵坐标使用笛卡尔坐标系中直线的截距b。由此我们可知,笛卡尔空间的一条直线映射到霍夫空间的一个确定点,霍夫空间内的一个点映射到笛卡尔空间的一条直线
而分析可知,笛卡尔坐标系中的一个点映射到霍夫坐标系中就是一条直线,那么我们从不同的角度分析笛卡尔空间中这两个点到霍夫空间的映射情况:
· 角度一:笛卡尔空间的一个点会映射为霍夫空间的一条线
· 角度二:笛卡尔空间的一条线会映射为霍夫空间的一个点
分析可知:
· 笛卡尔空间的两个点会映射为霍夫空间内两条相交于(k1, b1)的直线
· 这两个点对应的直线会映射为霍夫空间内的点(k1, b1)
换句话说,角度一决定了线条的数量,角度二决定了两条线相交的点
综上所述,在霍夫空间内,经过一个点的直线越多,说明其在笛卡尔空间内映射的直线是由越多的点所构成的,我们知道两个点就能构成一条直线,但是如果有一个点是由计算错误产生,那么它和另外一个点也会构成直线,此时就会凭空构造出一条实际上并不存在的直线。这种情况是我们极力要避免的,因此在计算中,我们希望用更多的点构造一条直线,以提高直线的可靠性。因此,霍夫变换选择直线的基本思路是:选择有尽可能多直线交汇的点。

上面都是以我们熟悉的笛卡尔空间为例说明的,在笛卡尔空间内,可能存在诸如x = x0的垂线形式,此时斜率为无穷大,截距b无法取值,因此无法映射到霍夫空间,为了解决上述问题,可以考虑将笛卡尔坐标系映射到极坐标系上
与笛卡尔空间和霍夫空间的映射关系类似:
· 极坐标系中的一个点映射为霍夫坐标系(霍夫空间)内的一条线(曲线)
· 极坐标系中的一条线映射为霍夫坐标系中的一个点
在霍夫坐标系中,经过一个点的线越多,说明其映射在极坐标内的直线是由越多的点所构成的。因此霍夫变换选择直线的基本思路是:选择由尽可能多线交汇的点。通常情况下,设置一个阈值,当霍夫坐标系内交于某点的曲线达到了阈值,就认为在对应的极坐标系内检测到一条直线
2)HoughLines函数
OpenCV提供了函数cv2.HoughLines()用来实现霍夫直线变换,该函数要求所操作的原图像是一个二值图像,所以在进行霍夫变换之前要先将原图像进行二值化,或者进行Canny边缘检测,该函数语法格式为:
Lines = cv2.HoughLines(image, rho, theta, threshold)
其中image为输入图像,必须是8位的单通道二值图像,rho为以像素为单位的距离r的精度,一般情况下,使用的精度是1;theta为角度θ的精度,一般情况下,使用的精度是π/180,表示要搜索所有可能的角度;threshold是阈值,该值越小,判定出的直线就越多;返回值lines中的每一个元素都是一对浮点数,表示检测到的直线的参数,即(r, θ)
在绘制线的时候,所使用的函数是cv2.line(),该函数方便的地方在于,即使点的坐标超出了图像的范围,它也能正确的画出线来
在一些情况下,使用霍夫变换可能会将图像中有限个点碰巧对齐的非直线关系检测为直线而导致误检测,尤其是一些背景很复杂的图形,误差会更明显,为了解决这个问题,人们提出了霍夫变换的改进版——概率霍夫变换
3)HoughLinesP函数
概率霍夫变换对基本霍夫变换算法进行了一点修正,是霍夫变换算法的优化。它没有考虑所有的点,相反,它只需要一个足以进行线检测的随机点子集即可
为了更好的判断直线,概率霍夫变换算法还对选取直线的方法进行了两点改进:
· 所接受直线的最小长度,如果小于该长度,认为这条直线仅仅是图形中若干个像素点恰好随机构成了一种算法上的直线关系而已,实际上原图中并不存在这条直线
· 接受直线时允许的最大像素点间距。如果有超过阈值个数的像素点构成了一条直线,但是这组像素点之间的距离都很远,就不会接受该直线作为判定结果
在OpenCV中,函数cv2.HoughLinesP()实现了概率霍夫变换,语法格式为:
Lines = cv2.HoughLinesP(image, rho, theta, threshold, minLingLength, maxLineGap)
其中,image是输入图像,必须为8位单通道二值图像;rho和theta以及threshold
和HoughLines函数相同,minLineLength用来控制“接受直线的最小程度”;maxLineGap用来控制接受共线线段之间的最小间隔,即在一条线中两点的最大间隔,默认值为0;返回值lines是由numpy.ndarray类型的元素构成的,其中每一个元素都是一对浮点数,表示检测到的直线的参数,即(r, θ)
2.霍夫圆环变换
霍夫变换除了用来检测直线以外,也能用来检测其他几何对象。实际上,只要是能够用一个参数方程表示的对象,都适合用霍夫变换来检测
用霍夫变换检测图像中的圆,与使用霍夫直线变换检测直线的原理类似。在霍夫圆变换中,需要考虑圆半径和圆心共三个参数,在OpenCV中,采取的策略是两轮筛选。第一轮筛选找出可能存在圆的位置;第二轮再根据第一轮的结果筛选出半径大小
与用来决定是否接受直线的两个参数“接受直线的最小长度”和“接受直线时允许的最大像素点间距”类似,霍夫圆变换也有几个用于决定是否接受圆的参数:圆心间的最小距离、圆的最小半径、圆的最大半径
在OpenCV中,实现霍夫圆变换的是函数cv2.HoughCircles(),该函数将Canny边缘检测和霍夫变换结合,语法格式为:
Circles = cv2.HoughCircles(image, method, dp, minDist, param1, param2, minRadius, maxRadius)
其中,image为输入图像,类型为8位的单通道灰度图像;method为检测方法,HOUGH_GRADIENT是唯一可用的参数值,该参数代表的是霍夫圆检测中两轮检测所使用的方法;dp为累加器分辨率,它是一个分割比率,用来指定图像分辨率与圆心累加器分辨率的比例;minDist为圆心间的最小间距,被作为阈值使用;param1这个参数是缺省的,默认值为100,对应的是Canny边缘检测的高阈值(低阈值是高阈值的二分之一);param2为圆心位置必须收到的投票数,只有在第一轮筛选过程中,投票数超过该值的圆才有资格进入第二轮的筛选,因此,该值越大,检测到的圆就越少,这个参数也是缺省的,默认值为100;minRadius为半径的最小值,该参数是缺省的,默认值为0,此时该参数不起作用;maxRadius为半径的最大值,该参数是缺省的,默认值为0,此时该参数不起作用;circles为返回值,由圆心和半径构成的numpy.ndarray
特别注意,在调用函数cv2.HoughLinesCircles()之前,要对源图像进行平滑操作,以减少图像中的噪声,避免发生误判

若有侵权,请联系删除

本读书笔记来源于教材。1


  1. 李立宗. OpenCV轻松入门: 面向python[M].北京. 电子工业出版社: 李立宗. 2019.5 ↩︎

你可能感兴趣的:(OpenCV学习,python,opencv,计算机视觉)