OpenCV

OpenCV 下载及官方英文文档

1. cv.imread 读

import numpy as np
import cv2 as cv
img = cv.imread("C:/Users/Rain/Desktop/000007.jpg")

2. cv.cvtColor 转换格式

import matplotlib.pyplot as plt
#修改其通道的形式
img_space = cv.cvtColor(img, cv.COLOR_BGR2RGB)
lunzi = img[200:330,270:330]
img[50:180,50:110] = lunzi
plt.imshow(img)
plt.show()

#第二种方式
b,g,r = cv.split(img)
img = cv.merge((r,g,b))
plt.imshow(img)
plt.show()

3. cv.copyMakeBorder 扩充边界

"""
给图像加入边框:
参数依次是,原图像,上下左右需要加的像素数
类型:
BORDER_DEFAULT:向外扩展,但是值选取镜像值
cv2.BORDER_REFLECT:也是选取镜像值,会镜像边缘值,123|321
cv2.BORDER_REFLECT_101:也是选取镜像值,但是镜像值不会镜像最边上的值,123|21
cv.BORDER_CONSTANT:利用常数填充
cv.BORDER_REPLICATE:边缘像素点的数值,向外扩展
cv.BORDER_WRAP:用一张相同的图片放在某个方向上,然后向外扩展多少像素就截取多少
"""
replicate = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT_101)
wrap = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_WRAP)
constant= cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_CONSTANT,value=BLUE)
plt.subplot 子图
plt.subplot(231)
plt.subplot(2,3,1)
#两行三列的大图,第一个子图

4. cv.threshold 利用阈值对图像进行选择(阈值化)

"""
函数 cv.threshold 对单通道数组应用固定阈值操作。
参数:
	原图
	阈值
	最大值(可能用到)
	类型:
		cv.THRESH_BINARY:某位置的像素值是否大于阈值,大于则置为最大值,反之则为0
		cv.THRESH_BINARY_INV:和上一个完全相反
		cv.THRESH_TRUNC:像素值大于阈值,则替换为最大值,反之则不变
		cv.THRESH_TOZERO:像素值大于阈值,则不变,反之则为0
		cv.THRESH_TOZERO_INV:像素值大于阈值,则为0,反之则不变
"""
ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY)
4.1 cv.adaptiveThreshold 自适应阈值

在光照变化图像下进行阈值化

th2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY,11,2)

"""
参数:
	1.源图像
	2.输出图像
	3.最大值
	4.领域内计算阈值方法:ADAPTIVE_THRESH_MEAN_C(计算领域平均值,再减去最后的偏移量) 和 ADAPTIVE_THRESH_GAUSSIAN_C(计算领域高斯均值,再减去最后的偏移量)
	5.阈值类型:THRESH_BINARY 和THRESH_BINARY_INV
	6.自适应领域块大小:一般为奇数
	7.偏移量
"""
4.2 Otsu算法

Otsu算法(大津法或最大类间方差法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个部分之间的灰度差异最小,通过方差的计算来寻找一个合适的灰度级别来划分。所以可以在二值化的时候采用otsu算法来自动选取阈值进行二值化。otsu算法被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响。因此,使类间方差最大的分割意味着错分概率最小。

5. cv.bitwise_and(not、or、xor) 筛选区域

"""
void bitwise_and() //dst = src1 & src2
void bitwise_or() //dst = src1 | src2
void bitwise_xor() //dst = src1 ^ src2
void bitwise_not() //dst = ~src
参数:
	输入图像1
	输入图像2(not没有这个)
	输出图像
	mask(掩膜)
	
掩膜
数字图像处理中,掩模为二维矩阵数组,有时也用多值图像,图像掩模主要用于:
	1.提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。 
	2.屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。 
	3.结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。 
	4.特殊形状图像的制作。

"""
mask_inv = cv.bitwise_not(mask)

6. cv.addWeighted 图像通过权重融合

img1 = cv.imread('ml.png')
img2 = cv.imread('opencv-logo.png')
#图片1,权重1,图片2,权重2,偏差
#注意这里融合的时候需要两张图篇共同大小
dst = cv.addWeighted(img1,0.7,img2,0.3,0)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()
6.1 PPT
import numpy as np
import cv2 as cv
import time
# 加载两张图片
img1 = cv.imread("C:/Users/Rain/Desktop/000007.jpg")
img2 = cv.imread("C:/Users/Rain/Desktop/000019.jpg")
l, h = img1.shape[0:2]
img2_R = cv.resize(img2, (h, l))
a=0
cv.namedWindow('ppt',True)
dst = cv.addWeighted(img1, a, img2_R, 1-a, -1)
cv.imshow('ppt', dst)
# cv.waitKey(0)
while a<1.0:
    dst = cv.addWeighted(img1, a, img2_R, 1-a, -1)
    cv.imshow('ppt', dst)
    cv.waitKey(100)
    a+=0.1

cv.waitKey(0)
cv.destroyAllWindows()

7 cv.getTickCount 类似time.time

e1 = cv.getTickCount()
# 你的执行代码
e2 = cv.getTickCount()
time = (e2 - e1)/ cv.getTickFrequency()

8. cv.inRange() 提取想要的颜色

import cv2 as cv
import numpy as np
cap = cv.VideoCapture(0)
while(1):
    # 读取帧
    _, frame = cap.read()
    # 转换颜色空间 BGR 到 HSV
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
    # 定义HSV中蓝色的范围
    lower_blue = np.array([110,50,50])
    upper_blue = np.array([130,255,255])
    # 设置HSV的阈值使得只取蓝色
    # 原图,低值数组,高值数组,选取数组范围内的颜色,置为mask
    mask = cv.inRange(hsv, lower_blue, upper_blue)
    # 将掩膜和图像逐像素相加
    res = cv.bitwise_and(frame,frame, mask= mask)
    cv.imshow('frame',frame)
    cv.imshow('mask',mask)
    cv.imshow('res',res)
    k = cv.waitKey(5) & 0xFF
    if k == 27:
        break
cv.destroyAllWindows()
    
"""
如果需要同时选取多个颜色的话,可以通过设置多个mask,通过相加的方式把mask加起来就行了
颜色的选取,主要是取决于数组高低值的设定,值设定的越准确,提取的效果就越好
"""
8.1 如何查找HSV的值
>>> green = np.uint8([[[0,255,0 ]]])
>>> hsv_green = cv.cvtColor(green,cv.COLOR_BGR2HSV)
>>> print( hsv_green )
[[[ 60 255 255]]]

#把[H- 10,100,100]和[H+ 10,255, 255]分别作为下界和上界。

9. cv.resize() 缩放或者放大图像

#两种不同的resize参数填写方式,填改变之后的大小或者是填写缩放比例fx,fy
import numpy as np
import cv2 as cv
img = cv.imread('messi5.jpg')
res = cv.resize(img,None,fx=2, fy=2, interpolation = cv.INTER_CUBIC)
#或者
height, width = img.shape[:2]
res = cv.resize(img,(2*width, 2*height), interpolation = cv.INTER_CUBIC)


"""
INTER_NEAREST - 最邻近插值
INTER_LINEAR - 双线性插值,如果最后一个参数你不指定,默认使用这种方法
INTER_AREA - resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
INTER_CUBIC - 4x4像素邻域内的双立方插值
INTER_LANCZOS4 - 8x8像素邻域内的Lanczos插值
"""

10. cv.warpAffine 仿射变换函数

10.1 平移

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nu9zMP87-1678070247586)(C:\Users\Rain\AppData\Roaming\Typora\typora-user-images\image-20220622161924559.png)]

import numpy as np
import cv2 as cv
img = cv.imread('messi5.jpg',0)
rows,cols = img.shape
#最后一个参数分别为,列数和行数(这里的100和50),列数和行数都是指平移的列数和行数数值
M = np.float32([[1,0,100],[0,1,50]])
dst = cv.warpAffine(img,M,(cols,rows))
cv.imshow('img',dst)
cv.waitKey(0)
cv.destroyAllWindows()
10.2 旋转

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XKs4Mhfx-1678070247588)(C:\Users\Rain\AppData\Roaming\Typora\typora-user-images\image-20220622162058196.png)]

img = cv.imread('messi5.jpg',0)
rows,cols = img.shape
# cols-1 和 rows-1 是坐标限制
M = cv.getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0),90,1)
dst = cv.warpAffine(img,M,(cols,rows))
cv.getRotationMatrix2D

上面没有改过的变换矩阵M的值,是在原图的基础上默认以图像左上角为旋转点进行旋转。但是一般来说,旋转时候的旋转点不会固定在左上角,而是很多其他地方,那么此函数就是用来选取旋转点,旋转角度和缩放比例的函数。

# 第一个参数旋转中心,第二个参数旋转角度,第三个参数:缩放比例
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 1)
# 得到矩阵后得用到图像的仿射变换函数才可以进行最终图像的变化
res = cv2.warpAffine(img, M, (cols, rows))
10.3 仿射变换
cv.getAffineTransform

同上述cv.getRotationMatrix2D一样,属于一种变换的规则。选取的是原图中的三个点和输出图像中三个点的位置,然后利用该函数创建一个2×3的矩阵,最后通过cv.warpAffine进行变换。

img = cv.imread('drawing.png')
rows,cols,ch = img.shape
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50],[100,250]])
M = cv.getAffineTransform(pts1,pts2)
dst = cv.warpAffine(img,M,(cols,rows))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
10.4 透视变换
cv.getPerspectiveTransform

同上,透视变换(Perspective Transformation)是将成像投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。提供四个点就可以计算一个对应的矩阵。

这里使用的是cv.warpPerspective而不是cv.warpAffine

img = cv.imread('sudoku.png')
rows,cols,ch = img.shape
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M = cv.getPerspectiveTransform(pts1,pts2)
dst = cv.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()
10.5 总结

其实对于上面旋转、仿射变换和透视变换来说,所提到的函数都是用来确定变换矩阵的函数,基于原图和变换好后的图像可以通过有限的点来计算出对应的矩阵。

思考:如果需要通过结果图像才能计算的话,那对于一个没有结果的图片,当需要进行变换的时候应该怎么办?

先验知识?

11. cv.filter2D() 2D卷积

将内核与图像进行卷积

#图像、深度、卷积核
dst=cv.filter2D(src, ddepth, kernel)

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('opencv_logo.png')
kernel = np.ones((5,5),np.float32)/25
dst = cv.filter2D(img,-1,kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dst),plt.title('Averaging')
plt.xticks([]), plt.yticks([])
plt.show()

12. 图像去模糊

通过将图像与低通滤波器内核进行卷积来实现图像模糊。这对于消除噪音很有用。它实际上从图像中消除了高频部分(例如噪声,边缘)。

12.1 平均

这是通过将图像与归一化框滤镜进行卷积来完成的。它仅获取内核区域下所有像素的平均值,并替换中心元素。

12.1.1 cv.blur()

3×3卷积核的值如下,如果不是3×3,是其他的大小,也是卷积核大小跟着变就行了,里面的值全是1,前面的数组也改成对应的个数即可。

这里的乘法不像高数里矩阵相乘,就是简单的对应位置相乘。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7e1Y9Fz2-1678070247589)(C:\Users\Rain\AppData\Roaming\Typora\typora-user-images\image-20220622191920095.png)]

void blur(InputArray src, 
          OutputArray dst,
          Size ksize,
          Point anchor = Point(-1,-1),
          int borderType = BORDER_DEFAULT );

"""
参数:
	输入图像
	输出图像
	卷积核大小
	Point类型的anchor,锚点,(-1,-1)默认表示锚点在核的中心
	边界模式,指定处理边界像素时如何确定图像范围外的像素的取值
"""
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('opencv-logo-white.png')
#这里就是函数使用方法
blur = cv.blur(img,(5,5))
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()
12.1.2 cv.boxFilter() 方框滤波
dst=cv2.boxFilter(src,ddepth,ksize,anchor,normalize,borderType)
"""
参数:
	原图
	深度,一般使用-1来代表与原图相同深度
	滤波核大小
	anchor,锚点
	normalize,是否进行归一化,1代表要进行,0不进行
	borderType是边界样式,该值决定了以何种方式处理边界
"""
12.1.3 方框滤波核均值滤波的区别

两者都是以方框的形式进行滤波,但是方框滤波和均值滤波之前的参数不一样

均值滤波之前的参数就是核大小的倒数,例如3×3,值就是1/9

方框滤波之前的值就不一样,由于normalize为1时,代表需要归一化,一个时候就需要进行归一化的操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-web0LC3K-1678070247590)(C:\Users\Rain\AppData\Roaming\Typora\typora-user-images\image-20220622195843801.png)]

12.2 高斯模糊
cv.GaussianBlur() 高斯滤波函数
dst = cv.GaussianBlur(src,dst,ksize,sigmaX.sigmaY,boderType)
"""
参数:
	输入图像
	输出图像
	内核大小
	高斯核在x方向的标准差
	高斯核在y方向的标准差(sigmaY=0时,其值自动由sigmaX确定(sigmaY=sigmaX);sigmaY=sigmaX=0时,它们的值将由ksize.width和ksize.height自动确定)
	像素外插策略
"""

#示例
blur = cv.GaussianBlur(img,(5,5),0)
cv.getGaussianKernel() 创建高斯内核
cv.getGaussianKernel (int ksize, double sigma, int ktype=CV_64F)

"""
参数:
	ksize:孔径大小。 它应该是奇数 (ksizemod2=1) 和正数。
	sigma:高斯标准差。 如果它是非正数,则根据 ksize 计算为
		sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8。
	ktype:滤波器系数的类型。 它可以是 CV_32F 或 CV_64F 。
"""
12.3 中位模糊
cv.medianBlur()

提取内核区域下所有像素的中值,并将中心元素替换为该中值。这对于消除图像中的椒盐噪声非常有效。有趣的是,在上述过滤器中,中心元素是新计算的值,该值可以是图像中的像素值或新值。但是在中值模糊中,中心元素总是被图像中的某些像素值代替。有效降低噪音。其内核大小应为正奇数整数。

median = cv.medianBlur(img,5)
12.4 双边滤波
cv.bilateralFilter()

在去除噪声的同时保持边缘清晰锐利非常有效。但是,与其他过滤器相比,该操作速度较慢。

我们已经看到,高斯滤波器采用像素周围的邻域并找到其高斯加权平均值。高斯滤波器仅是空间的函数,也就是说,滤波时会考虑附近的像素。它不考虑像素是否具有几乎相同的强度。它不考虑像素是否是边缘像素。因此它也模糊了边缘,这是我们不想做的。

双边滤波器在空间中也采用高斯滤波器,但是又有一个高斯滤波器,它是像素差的函数。空间的高斯函数确保仅考虑附近像素的模糊,而强度差的高斯函数确保仅考虑强度与中心像素相似的那些像素的模糊。由于边缘的像素强度变化较大,因此可以保留边缘。

blur = cv.bilateralFilter(img,9,75,75)

13. 形态学转换

13.1 cv.erode() 侵蚀

侵蚀的基本思想就像土壤侵蚀一样,它侵蚀前景物体的边界(尽量使前景保持白色)。它是做什么的呢?内核滑动通过图像(在2D卷积中)。原始图像中的一个像素(无论是1还是0)只有当内核下的所有像素都是1时才被认为是1,否则它就会被侵蚀(变成0)。

上述的另一种说法是,计算给定内核区域的局部最小值,当内核在图像上扫描时,我们计算由重叠的最小像素值,并用该最小值替换锚点下的图像像素。

erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor, int iterations,int borderType, constScalar& borderValue )

"""
参数:
	输入
	输出
	内核
	anchor:锚的位置,其有默认值(-1,-1),表示锚位于中心。
	iterations:用于迭代使用erode()函数的次数
	borderType:处理边界的模式
	borderValue:边界为常数时的边界值
"""
import cv2 as cv
import numpy as np
img = cv.imread('j.png',0)
kernel = np.ones((5,5),np.uint8)
erosion = cv.erode(img,kernel,iterations = 1)
13.2 cv.dilate() 扩张

它与侵蚀正好相反。如果内核下的至少一个像素为“ 1”,则像素元素为“ 1”。因此,它会增加图像中的白色区域或增加前景对象的大小。通常,在消除噪音的情况下,腐蚀后会膨胀。因为腐蚀会消除白噪声,但也会缩小物体。因此,我们对其进行了扩展。由于噪音消失了,它们不会回来,但是我们的目标区域增加了。在连接对象的损坏部分时也很有用。

上述的另一种说法是,当内核在图像上扫描时,我们计算由B重叠的最大像素值,并用该最大值替换锚点位置中的图像像素。您可以推断,这种最大化的操作会使图像中的亮区“增长”(因此称为扩张)。

dilation = cv.dilate(img,kernel,iterations = 1)
#他的参数和cv.erode()一样只不过内部的实现不一样
13.3 cv.morphologyEx() 的多种运算
void morphologyEx(Mat src, Mat dst, int op, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue)

"""
参数:
	其中op是指操作的类型,一共有如下几种类型
	enum MorphTypes{
        MORPH_ERODE    = 0, //腐蚀
        MORPH_DILATE   = 1, //膨胀
        MORPH_OPEN     = 2, //开操作,先侵蚀后扩张
        MORPH_CLOSE    = 3, //闭操作,先扩张后侵蚀
        MORPH_GRADIENT = 4, //梯度操作
        MORPH_TOPHAT   = 5, //顶帽操作,输入图像和图像开运算之后的差
        MORPH_BLACKHAT = 6, //黑帽操作,输入图像和图像闭运算之差。
        MORPH_HITMISS  = 7  
	};
"""

dilation = cv.dilate(img,kernel,iterations = 1) 
opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel) 
closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel) 
gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel) 
tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel) 
blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel) 

14. 图像梯度

如何理解说到的梯度,到底理解为边缘还是求导?

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('dave.jpg',0)
laplacian = cv.Laplacian(img,cv.CV_64F)
sobelx = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
sobely = cv.Sobel(img,cv.CV_64F,0,1,ksize=5)
plt.subplot(2,2,1)
plt.imshow(img,cmap = 'gray')
plt.title('Original')
plt.xticks([])
plt.yticks([])
plt.subplot(2,2,2)
plt.imshow(laplacian,cmap = 'gray')
plt.title('Laplacian')
plt.xticks([])
plt.yticks([])
plt.subplot(2,2,3)
plt.imshow(sobelx,cmap = 'gray')
plt.title('Sobel X')
plt.xticks([])
plt.yticks([])
plt.subplot(2,2,4)
plt.imshow(sobely,cmap = 'gray')
plt.title('Sobel Y')
plt.xticks([])
plt.yticks([])
plt.show()
14.1 拉普拉斯算子

Laplacian(拉普拉斯)算子是一种二阶导数算子,其具有旋转不变性,可以满足不同方向的图像边缘锐化(边缘检测)的要求。通常情况下,其算子的系数之和需要为零。

dst=cv2.Laplacian(src,ddepth,ksize,scale,delta,borderType)

"""
参数:
    dst代表目标图像。
    src代表原始图像。
    ddepth代表目标图像的深度。
    ksize代表用于计算二阶导数的核尺寸大小。该值必须是正的奇数。当ksize的值为1时,Laplacian算子计算时采用的 3×3的核如上所示。
    scale代表计算Laplacian值的缩放比例因子,该参数是可选的。默认情况下,该值为 1,表示不进行缩放。
    delta代表加到目标图像上的可选值,默认为0。
    borderType代表边界样式。
    
    通常情况下,在使用Laplacian算子时,对于参数ksize、scale、delta和borderType,直接采用其默认值即可。因此,函数cv2.boxFilter()的常用形式为:
    dst=cv2.Laplacian(src,ddepth)
"""
14.2 cv.Sobel() Sobel算子
void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size );

"""
参数列表:
    src 输入图像
    dst 输出图像
    xorder  x方向上的差分阶数
    yorder  y 方向上的差分阶数
    aperture_size  扩展 Sobel 核的大小,必须是 1, 3, 5 或7
"""

15. cv.Canny() Canny边缘检测

void cvCanny( const CvArr* image, CvArr* edges, double threshold1,double threshold2, int aperture_size=3 );

"""
参数:
	image:单通道输入图像.
	edges:单通道存储边缘的输出图像
	threshold1:第一个阈值
	threshold2:第二个阈值
	aperture_size:Sobel 算子内核大小 (见 cvSobel).
	函数 cv.Canny 采用 CANNY 算法发现输入图像的边缘而且在输出图像中标识这些边缘。threshold1和threshold2 当中的小阈值用来控制边缘连接,大的阈值用来控制强边缘的初始分割。
"""
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('C:/Users/Rain/Desktop/000007.jpg',0)
edges = cv.Canny(img,100,200)
plt.subplot(121)
plt.imshow(img,cmap = 'gray')
plt.title('Original Image')
plt.xticks([])
plt.yticks([])
plt.subplot(122)
plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image')
plt.xticks([])
plt.yticks([])
plt.show()

16. 图像金字塔

通常,我们过去使用的是恒定大小的图像。但是在某些情况下,我们需要使用不同分辨率的(相同)图像。例如,当在图像中搜索某些东西(例如人脸)时,我们不确定对象将以多大的尺寸显示在图像中。在这种情况下,我们将需要创建一组具有不同分辨率的相同图像,并在所有图像中搜索对象。这些具有不同分辨率的图像集称为“图像金字塔”(因为当它们堆叠在底部时,最高分辨率的图像位于顶部,最低分辨率的图像位于顶部时,看起来像金字塔)。

16.1 高斯金字塔 cv.pyrDown()

pyrDown,先用高斯核对图像进行卷积,然后删除所有偶数行和偶数列,新的到的图像面积就会变成源图像的四分之一。

平滑图片并下采样.

void pyrDown(Mat src, Mat dst, Size dstsize, int borderType)
"""
参数:
	原图像Mat对象
	目标图像Mat对象
	dstsize:目标图像的大小,只能输入为原图像的1/2(默认)
	boderType:边缘类型
"""
16.2 拉普拉斯金字塔 cv.pyrUp()

上采样图像然后平滑它。

void pyrUp(InputArray src, OutputArray dst, const Size& dstsize=Size());
"""
参数:
	原图像Mat对象
	目标图像Mat对象
	dstsize:目标图像的大小,默认为两倍大小
	boderType:边缘类型
"""
16.3 Orapple
# 3.使用图像金字塔创建一个新的水果,'Orapple'
import cv2
import numpy

A = cv2.imread("C:/Users/Rain/Desktop/1.jpg")
B = cv2.imread('C:/Users/Rain/Desktop/2.jpg')
print(A.shape)  # (256, 256, 3)
print(B.shape)  # (256, 256, 3)

# generate Gaussian pyramid for A
G = A.copy()
print(G)
gpA = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpA.append(G)

# generate Gaussian pyramid for B
G = B.copy()
gpB = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpB.append(G)

lpA = [gpA[5]]
for i in range(6,0,-1):
    print(i)
    GE = cv2.pyrUp(gpA[i])
    GE=cv2.resize(GE,gpA[i - 1].shape[-2::-1])
    L = cv2.subtract(gpA[i-1],GE)
    lpA.append(L)

# generate Laplacian Pyramid for B

lpB = [gpB[5]]
for i in range(6,0,-1):
    print(i)
    GE = cv2.pyrUp(gpB[i])
    GE = cv2.resize(GE, gpB[i - 1].shape[-2::-1])
    L = cv2.subtract(gpB[i-1],GE)
    print(L.shape)
    lpB.append(L)

# Now add left and right halves of images in each level
LS = []
lpAc=[]
for i in range(len(lpA)):
    b=cv2.resize(lpA[i],lpB[i].shape[-2::-1])
    lpAc.append(b)
print(len(lpAc))
print(len(lpB))
j=0
for i in zip(lpAc,lpB):
    la,lb = i
    rows,cols,dpt = la.shape
    ls = np.hstack((la[:,0:cols//2], lb[:,cols//2:]))
    j=j+1
    LS.append(ls)

ls_ = LS[0]
for i in range(1,6):
    ls_ = cv2.pyrUp(ls_)
    ls_= cv2.resize(ls_, LS[i].shape[-2::-1])
    ls_ = cv2.add(ls_, LS[i])

# image with direct connecting each half
B= cv2.resize(B, A.shape[-2::-1])
real = np.hstack((A[:,:cols//2],B[:,cols//2:]))
cv2.imwrite('C:/Users/Rain/Desktop/Pyramid_blending2.jpg',ls_)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值