纯手打持续更新中~
1、轮廓检测(findContours)
cv2.findContours (img,mode,method)
mode:轮廓检索模式
-
RETR_EXTERNAL :只检索最外面的轮廓;
-
RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
-
RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
-
RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;(最常用这个)
method:轮廓逼近方法
-
CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
-
CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
-

输入图像的要求,必须是二值的!(更高的准确率)
python
img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 这一步对图像二值处理
cv_show(thresh,'thresh')

python
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
binary 为二值化之后的结果
contours为轮廓信息
hierarchy 表示层级
绘制轮廓(drawContours)
python
#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
# 注意需要copy,要不原图会变。。。
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
cv_show(res,'res')
python
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, 0, (0, 0, 255), 2)
cv_show(res,'res')
轮廓特征与近似(contourArea)
轮廓特征计算
python
cnt = contours[0]
#面积
cv2.contourArea(cnt)
#周长,True表示闭合的
cv2.arcLength(cnt,True)
轮廓近似

python
img = cv2.imread('contours2.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
draw_img = img.copy()
res = cv2.drawContours(draw_img, [cnt], -1, (0, 0, 255), 2)
cv_show(res,'res')

这里用到了近似函数approxPolyDP
python
epsilon = 0.15*cv2.arcLength(cnt,True) # 0.15 越小是越貼合的
approx = cv2.approxPolyDP(cnt,epsilon,True) #cnt是轮廓,epsilon是指定需要比较的值,一般是周长的倍数
draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
cv_show(res,'res')

2、模板匹配(matchTemplate)
两张图片,现在是要看第一张图片是在第二张图片的哪一个部分。

把右边的图片分成九宫格,然后opencv会从左到右,从上到下进行一点点的匹配(逐像素匹配,像素点的差异),看看左边的图像是在右边的哪个位置。
模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv里有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。假如原图形是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1)
模板匹配的代码(代码在notebook中运行):
python
# 模板匹配
img = cv2.imread('lena.jpg', 0)
template = cv2.imread('face.jpg', 0)
h, w = template.shape[:2]
img.shape # 输出(263, 263)
template.shape # 输出(110, 85)
有以下6种差异计算方法:
-
TM_SQDIFF:计算平方不同,计算出来的值越小,越相关
-
TM_CCORR:计算相关性,计算出来的值越大,越相关
-
TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
-
TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关(推荐用归一化的,结果会更可靠一些。)
-
TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关
-
TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关
-
公式:https://docs.opencv.org/3.3.1/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a2d7583695d
python
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
cv2.minMaxLoc() 是专门用于提取匹配结果矩阵(res)中极值(最小值 / 最大值) 及对应坐标的核心函数.
最小值就是根据需要匹配的图中,找到原图中的一个匹配点,后续根据h和w就能画出一个候选的方框。
python
res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)
res.shape # (154, 179)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # min_val:39168.0 max_val:74403584.0 min_loc:(107, 89) max_loc:(159, 62)
python
for meth in methods:
img2 = img.copy()
# 匹配方法的真值
method = eval(meth)
print (method)
res = cv2.matchTemplate(img, template, method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# 如果是平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED,取最小值
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
# 画矩形
cv2.rectangle(img2, top_left, bottom_right, 255, 2)
plt.subplot(121), plt.imshow(res, cmap='gray')
plt.xticks([]), plt.yticks([]) # 隐藏坐标轴
plt.subplot(122), plt.imshow(img2, cmap='gray')
plt.xticks([]), plt.yticks([])
plt.suptitle(meth)
plt.show()
示例

如果是匹配多个对象
python
img_rgb = cv2.imread('mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.jpg', 0)
h, w = template.shape[:2]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 取匹配程度大于%80的坐标
loc = np.where(res >= threshold)
for pt in zip(*loc[::-1]): # *号表示可选参数
bottom_right = (pt[0] + w, pt[1] + h)
cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)
cv2.imshow('img_rgb', img_rgb)
cv2.waitKey(0)

3、图像金字塔(pyrUp,pyrDown)
把图像组合成金字塔的形状,可以用于图像特征提取,每层的特征提取的结果组合在一起。

高斯 金字塔:向下采样方法(缩小)用高斯核,然后把偶数列全部去掉。

高斯 金字塔:向上采样方法(放大)
用相同的卷积核来卷积,可以想象10这个像素平均的分给了周围的像素点。

代码实验
python
img=cv2.imread("AM.png")
cv_show(img,'img')
print (img.shape) # (442, 340, 3)

python
# 上采样
up=cv2.pyrUp(img)
cv_show(up,'up')
print (up.shape) #(884, 680, 3)
python
#下采样方法
down=cv2.pyrDown(img)
cv_show(down,'down')
print (down.shape) # (221, 170, 3)
拉普拉斯金字塔
拉普拉斯金字塔的每一层 = 当前层的高斯图像 - 上采样后的下一层高斯图像。

python
down=cv2.pyrDown(img)
down_up=cv2.pyrUp(down)
l_1=img-down_up
cv_show(l_1,'l_1')