计算机视觉 实验四 Image_Processing5
目录
-
- 3.6 图像金字塔与轮廓检测
-
- 3.6.1 图像金字塔
-
Section 3.6.2: Laplacian Pyramid
-
Image Contour Analysis
-
What constitutes a contour?
-
A contour can be simply defined as the curve connecting all continuous points of equal intensity or color along an edge.
-
Contour analysis serves as a valuable tool for shape analysis and object detection/identification tasks.
-
Contour Features
-
Contour Approximation
-
Template Matching
-
six different comparison methods
-
multi-template matching approach
3.6 图像金字塔与轮廓检测
3.6.1 图像金字塔



import cv2 #opencv 读取进来为BGR格式
import matplotlib.pyplot as plt
import numpy as np
#一个魔法指令,不需要采用plt.show()显示图像
%matplotlib inline
代码解读
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码解读
img = cv2.imread('images/lena.jpg')
cv_show('lena',img)
print(img.shape)
print(img)
代码解读

up = cv2.pyrUp(img) # cv2.pyrUp() 从一个低分辨率小尺寸的图像向下构建一个金子塔
#尺寸变大,同时图片变糊
#将图像在每个方向上扩大为原来的两倍,新增的行和列以0填充,再使用先前同样的内核(乘以4)与放大后的图像卷积,获得近似值
cv_show("up",up)
print(up.shape) #(600,600,3)
代码解读


down = cv2.pyrDown(img) #cv2.pyrDown() 从一个高分辨率大尺寸的图像向上构建一个金字塔
#尺寸变小,同时图片变糊,分辨率降低
#pyrdown是pyrup将矩阵与高斯内核卷积,再将所有偶数列行和列去除
cv_show('down', down)
print(down.shape) #(150,150,3)
代码解读


up2 = cv2.pyrUp(up) #再次pyrUp
cv_show('up2',up2)
print(up2.shape) #(1200,1200,3)
代码解读


up = cv2.pyrUp(img)
up_down = cv2.pyrDown(up) #在pyrUp基础上再pyrDown
cv_show('img_up_down',up_down)
print(up_down.shape)
print(up_down)
res = np.hstack((img,up_down))#虽然图像大小不变但是先pyrUp再pyrDown的图片变得模糊了
cv_show('res',res)
cv_show('img-updown',img-up_down) #原图和处理后的图像差值
代码解读



3.6.2 拉普拉斯金字塔
down = cv2.pyrDown(img)
up_down = cv2.pyrUp(down)
res2 = img- up_down
cv_show('Laplace',res2)#这个图色彩更加丰富,说明先pyrDown再pyrUp的损失更大
代码解读

3.6.2 图像轮廓
什么是轮廓?
即为连接具有相同颜色或强度的所有连贯的点(沿着边界)所形成的曲线。这种曲线在形状分析方面发挥着重要作用,并被用来进行对象检测和识别等任务。
- 以更高的精度,请使用二进制图像;为此,在发现边界之前,请应用阈值或Canny边缘检测。
- 自OpenCV 3.2版本起始点以来, findContours()不再修改源图像.
- 在OpenCV环境中, 发现边界类似于在暗背景下识别亮体; 因此,请记住,要识别的目标应为明亮物体,背景应为黑暗区域.
img = cv2.imread('images/test2.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #灰度化
ret, thresh = cv2.threshold(gray, 127,255, cv2.THRESH_BINARY) #变成二值图像
cv_show('thresh', thresh)
代码解读

contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #全部轮廓,函数只保留终点部分
代码解读
np.array(contours).shape #轮廓的大小
代码解读

# 绘制轮廓
# 使用cv.drawContours函数。只要有边界点,它也可以用来绘制任何形状。它的第一个参数是源图像,第二个参数是应该作为Python列表传递的轮廓
# 第三个参数是轮廓的索引(在绘制单个轮廓时有用。要绘制所有轮廓,请传递-1),其余参数是颜色,厚度等等.
# 注意需要copy,要不原图像会变。。。
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0,0,255),2) #第三个参数如果填-1是找出所有的轮廓,是0就找出第一条轮廓
cv_show('res', res)
cv_show('img',img)
代码解读


draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, 0, (0,255,0),2)
cv_show('res', res)
cv_show('img',img)
代码解读


res = cv2.drawContours(img, contours, -1, (0,0,255),2) #直接对原图像进行操作,所以需要将原图像进行copy一下再进行操作
cv_show('res', res)
cv_show('img',img)
代码解读


轮廓特征
cnt = contours[0]
#print(contours)
代码解读
# 面积
area = cv2.contourArea(cnt)
#area1 = int(M["m00"]) #轮廓的面积也可以通过矩来表示
print(area)
代码解读

# 轮廓周长, True表示闭合的
perimeter = cv2.arcLength(cnt,True)
print(perimeter)
代码解读

# 特征矩
M = cv2.moments(cnt)
#print( M )
# 质心
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
print(cx,cy)
代码解读

轮廓近似
img2 = cv2.imread('images/star.png')
img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(img2_gray,127,255,0)
contours,hierarchy = cv2.findContours(thresh, 1, 2)
draw_img = img2.copy()
res = cv2.drawContours(img2,contours, -1, (0,0,255),2)
cv_show('res', res)
cnt = contours[0]
代码解读

epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
draw_img = img2.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0,255,0),2)
cv_show('res', res)
代码解读

模板匹配
基于卷积神经网络的方法在模式识别中表现优异。该算法通过将二维核在原始图像上以起始点为基础进行滑动操作,在图像上被该核覆盖的部分进行特征提取。具体而言,在OpenCV框架下提供了六种差异度计算方法,并将每一步骤所得结果存入预设大小矩阵作为最终输出结果。假设输入图像尺寸为A×B,则输出矩阵尺寸应为(A−a+1)×(B−b+1),其中a×b表示核的尺寸参数。
# 模板匹配
img = cv2.imread('images/lena.jpg',0)
template = cv2.imread('images/face.jpg',0)
h, w = template.shape[:2]
代码解读
img.shape
代码解读

template.shape
代码解读

采用平方差异度量(TM_SQDIFF),其结果数值低则表示数据点间关联性强。
通过余弦相似度(TM_CCORR)衡量数据间的相似程度,则结果数值越高表示相似程度越高。
使用皮尔逊相关系数(TM_CCOEFF)评估变量间的关系强度,则其结果数值越大反映变量间关联性越高。
采用归一化的平方差异度量(TM_SQDIFF_NORMED),其结果数值趋近于零表明数据高度一致。
通过归一化的余弦相似度(TM_CCORR_NORMED)衡量数据间的相似程度,则其结果数值接近于1则表示高度相似性。
使用归一化的皮尔逊相关系数(TM_CCOEFF_NORMED),其结果数值趋近于1则显示变量间的紧密关系。
列表中所有的6种比较方法
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
代码解读
res = cv2.matchTemplate(img,template,cv2.TM_SQDIFF)
print(res.shape)
代码解读

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
代码解读




img = cv2.imread('images/lena.jpg',0)
img2 = img.copy()
template = cv2.imread('images/face.jpg',0)
w, h = template.shape[::-1]
# 列表中所有的6种比较方法
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
for meth in methods:
img = img2.copy()
method = eval(meth)
# 应用模板匹配
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(img,top_left, bottom_right, 255, 2)
plt.subplot(121),plt.imshow(res,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img,cmap = 'gray')
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
plt.suptitle(meth)
plt.show()
代码解读



多对象的模板匹配
当我们需要寻找频繁出现的目标时, OpenCV中的cv.minMaxLoc()函数无法返回全部匹配位置.因此,在此情况下我们建议采用阈值化方法来解决这个问题.
img_rgb = cv2.imread('images/mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('images/mario_coin.jpg',0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
# 取匹配程度大于80%的坐标
threshold = 0.8
loc = np.where( res >= threshold)
img_rgb2 = img_rgb.copy()
for pt in zip(*loc[::-1]): #*号表示可选参数
cv2.rectangle(img_rgb2, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
#cv2.imwrite('res.png',img_rgb)
cv_show('img_rgb',img_rgb2)
#res = np.stack((img_rgb,img_rgb2))
#cv_show('res',res)
代码解读

