图像金字塔是有一副图像的多个不同分辨率的子图构成的图像集合。这组图像是由单个图像通过不断的降采样所产生的,最小的图像可能仅仅有一个像素点。金字塔从低向上分辨率逐渐降低
通常,图像金字塔底部是待处理的高分辨率图像(原始图像),顶部为低分辨率的近似图像,通常来说每向上移动一级,图像的高和宽都降低为原来的一半,大小变为原来的 1/4
图像金字塔是通过原图像不断向下采样而产生的,即由高分辨率的图像产生低分辨率的近似图像。
简单的图像金字塔可以通过不断的删除图像的偶数行和偶数列获得。也可以对原图滤波,得到原始图像的近似图像然后删除近似图像的偶数行偶数列。滤波器可以选择:
另外向上,向下采样两种操作不可逆,他们得到的图像也不能恢复原始状态了,
dst = cv2.pyrDown( src[, dstsize[, borderType]] )
这个实现了向下采样
默认,输出的图像大小为Size((src.cols+1)/2, (src.rows+1)/2)
dst = cv2.pyrUp( src[, dstsize[, borderType]] )
实现图像金字塔的向上采样
默认情况下,目标图像的大小为 Size(src.cols2, src.rows2),虽然要将高斯滤波器的系数乘以4,但是Opencv 库的目的就是要我们忽略这些细节,,所以不用太纠结为什么。。
o=cv2.imread('5.jpg')
r1=cv2.pyrUp(o)
r2=cv2.pyrDown(r1)
diff=r2-o # 构造 diff 图像,查看 down 与 o 的区别
cv2.imshow("original",o)
cv2.imshow("r1",diff)
cv2.imshow('r2',r2)
cv2.waitKey()
cv2.destroyAllWindows()
当然放大后也会变模糊,并且放大再缩小,也回不到原图的分辨率了。右图显示的是放大缩小后与原图像素值的插值。
这个就是通过金字塔的小图像进行向上采样获取完整的大尺寸高分辨率图像
一个图像经过向下采样,必然会失去一些信息,再向上采样就不会恢复,为了再向上采样时可以恢复,就要获取再采样过程中丢失的信息,这些丢失的信息就构成了拉普拉斯金字塔Li = Gi - pyrUp(Gi + 1)
Li Gi 分别表示拉普拉斯金字塔和高斯金字塔。
拉普拉斯金字塔中的第 i 层,等于“高斯金字塔中的第 i 层”与“高斯金字塔中的第 i+1 层的向上采样结果”之差。
问题是图像的尺寸问题,如果不是偶数最后就减不了,,比如(707,500,3) 经过一次向下一次向上就变成了 (708,500,3) 。。这是无法相减的,只能修修尺寸了吧。。
拉普拉斯金字塔的作用在于可以恢复高分辨率的图像,将G1 与 L0 相加就可以获得高分辨率的G0
o=cv2.imread('14.jpg')
G0=o
G1=cv2.pyrDown(G0)
G2=cv2.pyrDown(G1) # 构建高斯金字塔
G3=cv2.pyrDown(G2)
L0=G0-cv2.pyrUp(G1)
L1=G1-cv2.pyrUp(G2) # 拉普拉斯金字塔
L2=G2-cv2.pyrUp(G3)
RG0=L0+cv2.pyrUp(G1) # 其实就是上面式子的移项
print('G0.shape=',G0.shape)
print('RG0.shape=',RG0.shape)
result=RG0-G0 #将 RG0 和 G0 相减 # 获得的result 是一个数组
result=abs(result)
print("原始图像 G0 与恢复图像 RG0 差值的绝对值和:",np.sum(result)) # 结果是0,表示两个图像是一样的。
其他的层也一样。。使用拉普拉斯金字塔恢复的图像与原始图像完全一致。
边缘检测虽然可以检测出边缘 但边缘是不连续的,检测到的边缘不一定是一个整体,图像轮廓是指将边缘连接起来后形成的一个整体,用于后续的计算。使用 cv2.findCountours() 来查找轮廓, cv2.drawContours() 绘制轮廓。图像轮廓是图像中非常重要的一个特征信息,通过对图像轮廓的操作,可以获取目标图像的大小,位置方向等信息。、
一个轮廓对应一系列的点,这些点以某种方式表示图像的一条曲线,findContours() 用于查找图像的轮廓,并可以根据参数返回特定表示方式的轮廓,drawContours() 可以将查找的轮廓绘制到图像上,可以根据参数绘制不同样式的轮廓(实心空心,线条粗细颜色等),可以绘制全部轮廓也可以绘制部分。
contours, hierarchy = cv2.findContours( image, mode, method)
每个轮廓 contours[i] 对应4个元素来说明当前轮廓的层次关系[Next,Previous,First_Child,Parent]
print(hierarchy) 来查看hierarchy 的值,需要注意轮廓的层次结构是由参数 mode 决定的,不同的 mode 得到的轮廓的编号不一样,hierachy 也不一样。
cv2.RETR_EXTERNAL:只检测外轮廓。
输出值 [1,-1,-1,-1] 表示第零个轮廓的层次,后一个轮廓是第一个轮廓,前一个轮廓不存在所以两个 -1,不存在父轮廓,第四个参数也是 -1. [ -1 0 -1 -1] 同理,后一个轮廓不存在,前一个轮廓是0,不存在父子轮廓。
cv2.RETR_LIST:对检测到的轮廓不建立等级关系。
这里就检测出来三个轮廓,由于不建立等级关系,所以没有父子轮廓。
cv2.RETR_CCOMP:检索所有轮廓并将它们组织成两级层次结构。上面的一层为外边界,下面的一层为内孔的边界。如果内孔内还有一个连通物体,那么这个物体的边界仍然位于顶层。
额,这前一个轮廓就很迷,应该是说同一个层级的前一个轮廓吧,,上面的都是一个层级,这有两个了、
使用 cv2.findContours() 查找图像轮廓时,需要注意:
image=cv2.drawContours( image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]] )
import cv2
o = cv2.imread('12.jpg')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY) # 转换为灰度二值图
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, # 找边界
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
o=cv2.drawContours(o,contours,-1,(0,0,255),5) # 绘制边界,红色,画笔粗细为5
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()
import numpy as np
o = cv2.imread('16.jpg')
cv2.imshow("original",o) # 逐个显示一副图像内的边缘信息。
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
n=len(contours)
contoursImg=[]
for i in range(n):
temp=np.zeros(o.shape,np.uint8)
contoursImg.append(temp)
contoursImg[i]=cv2.drawContours(contoursImg[i],contours,i,(255,255,255),5)
cv2.imshow("contours[" + str(i)+"]",contoursImg[i])
cv2.waitKey()
cv2.destroyAllWindows()
o = cv2.imread('6.jpg')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
mask=np.zeros(o.shape,np.uint8)
mask=cv2.drawContours(mask,contours,-1,(255,255,255),-1) # thickness设置为-1,绘制前景对象的实心轮廓
cv2.imshow("mask" ,mask)
loc=cv2.bitwise_and(o,mask) # 实现轮廓与原始图像进行按位与,可以将前景对象从原始图像中提取出来
cv2.imshow("location" ,loc)
cv2.waitKey()
cv2.destroyAllWindows()