Python OpenCV8:OpenCV 模板匹配、霍夫变换

1. 模板匹配

模板匹配:在给定的图片中找到与模板最相似的区域。思路是按照滑动窗口的思路不断移动模板图片,并计算它和图像对应区域的匹配度,最终选择匹配度最高的区域作为最终结果。

对于该图像和模板:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第1张图片

 

要识别匹配区域,我们必须通过滑动来比较模板图像与源图像:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第2张图片

模板块从左到右、从上到下每次移动一个像素,在每个位置计算与模板图像的相似度,结果存储在结果矩阵中。 如果输入图像的大小 W*H 和模板图像的大小 w*h ,则输出矩阵R的大小为(W-w + 1,H-h + 1),并将R显示为图像。

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第3张图片

得到上图后,找到最大值的位置,则认为该位置对应的区域是最佳匹配,对应的区域是一个以该点为顶点,大小与模板图像相同的矩阵。 

模板匹配不适用于尺度变换,视角变换后的图像。

cv.matchTemplate(img, template, method)

参数:

img 要进行模板匹配的图像

template 模板

method 实现模板匹配的算法:

CV_TM_SQDIFF 平方差匹配:利用模板与图像之间的平方差进行匹配,最好的匹配是0,匹配越差,匹配的值越大。

CV_TM_CCORR 相关匹配:利用模板与图像间的乘法进行匹配,数值越大表示匹配程度较高,越小表示匹配效果差。

CV_TM_CCOEFF 相关系数匹配:利用模板与图像间的相关系数匹配,1表示完美的匹配,-1表示最差的匹配。

完成匹配后,使用cv.minMaxLoc()方法查找最大值所在的位置即可。如果使用平方差作为比较方法,则最小值位置是最佳匹配位置。 

例1:载入要搜索的图像和模板,实现模板匹配,定位最匹配的区域,并用矩形标注。

图像:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第4张图片

模板:

import matplotlib
import cv2 as cv
import matplotlib.pyplot as plt

font = {
    "family": "Microsoft YaHei"
}
matplotlib.rc("font", **font)

img = cv.imread("./image/wulin.jpeg")
template = cv.imread('./image/bai.jpeg')

# 模板匹配
res = cv.matchTemplate(img, template, cv.TM_CCORR)
# 获得位置
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
# max_loc为模板对应位置的左上角
top_left = max_loc
# 获取模板的高和宽
h, w = template.shape[:2]
# 获取模板对应位置的右下角
bottom_right = (top_left[0] + w, top_left[1] + h)
# 绘制矩形
cv.rectangle(img, top_left, bottom_right, (0, 255, 0), 2)

plt.imshow(img[:, :, ::-1])
plt.title("模板匹配结果")
plt.show()

输出:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第5张图片 

2. 霍夫直线检测

霍夫变换常用于提取图像中的线、圆等几何形状。

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第6张图片

在笛卡尔坐标系中,一条直线由 A=(x1,y1) 和 B=(x2,y2) 两点确定。

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第7张图片

直线 y=kx+q 可以写成关于 (k,q) 的函数表达式:

对应的变换用图形直观表示:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第8张图片

变换后的空间称为霍夫空间。即:笛卡尔坐标系中的一条直线对应霍夫空间中的一个点。反过来,同样成立,霍夫空间中的一条线对应笛卡尔坐标系中的一个点。

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第9张图片

两点 A 和 B 对应于霍夫空间:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第10张图片

三点共线的情况:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第11张图片

可以看出,如果笛卡尔坐标系中的点共线,则这些点在霍夫空间中的对应直线相交于一点。 如果有多条直线,如下图:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第12张图片

我们选择尽可能多的直线会聚点。上图中三条直线形成的两点A和B对应的是笛卡尔坐标系中的直线:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第13张图片

至此我们似乎已经完成了霍夫变换的求解。但如果情况如下图:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第14张图片

上图中的直线是x=2。为了确定(k,q),我们考虑将笛卡尔坐标系转换为极坐标。

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第15张图片

在极坐标中也是如此。极坐标中的点对应于霍夫空间的直线。此时霍夫空间不再是参数(k,q)的空间,而是(ρ,θ)空间, ρ为原点到直线的垂直距离,θ\表示直线的垂线与水平轴顺时针方向的夹角,垂线的夹角为0度,水平线的角度为 180 度。

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第16张图片

只需要求得交点在霍夫空间中的位置,就可以得到原始坐标系中的直线。

cv.HoughLines(img, rho, theta, threshold)

参数:

img 检测的图像,要求是二值化的图像,所以在调用霍夫变换之前首先要进行二值化,或者进行Canny边缘检测。

rho、theta ρ 和 θ 的精确度

threshold 阈值,只有累加器中的值高于该阈值时才被认为是直线。

返回值:

直线列表,列表中的元素为每条直线的rho、theta值。

例2:检测下图中的直线,并标注。

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第17张图片

import matplotlib
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

font = {
    "family": "Microsoft YaHei"
}
matplotlib.rc("font", **font)

img = cv.imread("./image/rili.jpg")

# 边缘检测,二值化
edges = cv.Canny(img, 50, 150)

# 霍夫直线检测
lines = cv.HoughLines(edges, 0.8, np.pi / 180, 180)

# 绘制直线
for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = rho * a
    y0 = rho * b
    x1 = int(x0 + 1000 * (-b))
    y1 = int(y0 + 1000 * a)
    x2 = int(x0 - 1000 * (-b))
    y2 = int(y0 - 1000 * a)
    cv.line(img, (x1, y1), (x2, y2), (0, 255, 0))

plt.imshow(img[:, :, ::-1])
plt.title("霍夫直线检测结果")
plt.show()

输出:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第18张图片

3. 霍夫圆检测

OpenCV 使用霍夫梯度法来检测圆。

霍夫梯度法分两个阶段检测霍夫圆的范围。第一阶段检测圆心,第二阶段利用圆心推导出圆的半径。

圆心检测的原则:圆心为圆周法线的交点。设置一个阈值,如果某一点相交的直线条数大于该阈值,则认为该交点为圆心。

圆半径检测的原则:圆心到圆周的距离(半径)相同,确定一个阈值。只要相同距离的个数大于阈值,就认为距离是圆心的半径。

原则上,霍夫变换可以检测任何形状,但复杂的形状需要更多的参数,霍夫空间有更多的维度。因此,程序执行所需的内存空间和运行效率不利于标准霍夫变换用于实际复杂图形的检测。

由于霍夫圆检测对噪声比较敏感,所以首先需要对图像进行中值滤波。

cv.HoughCircles(image, method, dp, minDist, param1=100, param2=100, minRadius=0,maxRadius=0)

参数:

image 输入灰度图像

method 使用霍夫变换圆检测的算法,它的参数是CV_HOUGH_GRADIENT

dp 霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一半,以此类推。

minDist 圆心之间的最小距离,如果检测到的两个圆心之间距离小于该值,则认为它们是同一个圆心

param1 边缘检测时使用Canny算子的高阈值,低阈值是高阈值的一半。

param2 检测圆心和确定半径时所共有的阈值。

minRadius、maxRadius 检测到的圆半径的最小值和最大值。

返回值:

circles 输出圆向量,包括三个浮点型的元素:圆心横坐标、圆心纵坐标、圆半径。

例3:检测下图中的圆,并标注。

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第19张图片

输出:

Python OpenCV8:OpenCV 模板匹配、霍夫变换_第20张图片

你可能感兴趣的:(Python,python,opencv)