大四毕业后的这个暑假正式开始学习openCV
参考教程:唐宇迪老师: https://www.bilibili.com/video/BV1tb4y1C7j7
1.傅里叶变换
傅里叶变换的作用
高频:变化剧烈的灰度分量,例如边界
低频:变化缓慢的灰度分量,例如一片大海
滤波:
低通滤波器:只保留低频,会使图像模糊
高通滤波器:只保留高频,会使得图像细节增强
opencv中主要是cv2.dft()
和cv2.idft()
,输入图像需要先转换成np.float32
格式。
得到的结果中频率为0的部分会在左上角,通常需要转换到中心位置,可以通过shift实现。
cv2.dft()
返回的结果是双通道的(实部,虚部),通常还需要转换成图像格式才能展示(0,255)。
一些函数说明:
cv2.dft(img, cv2.DFT_COMPLEX_OUTPUT)
进行傅里叶变化参数说明: img表示输入的图片, cv2.DFT_COMPLEX_OUTPUT表示进行傅里叶变化的方法
np.fft.fftshift(img)
将图像中的低频部分移动到图像的中心参数说明:img表示输入的图片
cv2.magnitude(x, y)
将sqrt(x^2 + y^2) 计算矩阵维度的平方根参数说明:需要进行x和y平方的数
4.np.fft.ifftshift(img)
# 进图像的低频和高频部分移动到图像原来的位置
参数说明:img表示输入的图片
5.cv2.idft(img)
# 进行傅里叶的逆变化
参数说明:img表示经过傅里叶变化后的图片
demo1:
import cv2
import numpy as np
import matplotlib.pyplot as plt
'''
第一步:载入图片
第二步:使用np.float32进行格式转换
第三步:使用cv2.dft进行傅里叶变化
第四步:使用np.fft.shiftfft将低频转移到中间位置
第五步:使用cv2.magnitude将实部和虚部投影到空间域
第六步:进行作图操作
'''
img = cv2.imread('D:\\openCV files\\data\\2\\lena.jpg',0)#0表示灰度图
img_float32 = np.float32(img)#必须转换
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)#将左上角的低频移动至中心
#得到灰度图能表示的形式
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))#0,1表示实部虚部两个通道,:,:,表示图像像素坐标,20*log,是将结果映射到0-255的公式
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'),plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'),plt.xticks([]),plt.yticks([])
plt.show()
demo2:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 第一步读入图片
img = cv2.imread('D:\\openCV files\\data\\2\\lena.jpg',0)#0表示灰度图
# 第二步:进行数据类型转换
img_float32 = np.float32(img)#必须转换
# 第三步:使用cv2.dft进行傅里叶变化
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
# 第四步:使用np.fft.fftshift将低频转移到图像中心
dft_shift = np.fft.fftshift(dft)#将左上角的低频移动至中心
# 第五步:定义掩模:生成的掩模中间为1周围为0
rows, cols = img.shape
crow, ccol = int(rows/2), int(cols/2) #中心位置,方便确定掩膜
#低通滤波
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
# 第六步:将掩模与傅里叶变化后图像相乘,保留中间部分
fshift = dft_shift*mask
# 第七步:使用np.fft.ifftshift(将低频移动到原来的位置
f_ishift = np.fft.ifftshift(fshift)
# 第八步:使用cv2.idft进行傅里叶的反变化
img_back = cv2.idft(f_ishift)
# 第九步:使用cv2.magnitude转化为空间域内
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
# 第十步:进行绘图操作
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'),plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'),plt.xticks([]),plt.yticks([])
plt.show()
demo3:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 第一步读入图片
img = cv2.imread('D:\\openCV files\\data\\2\\lena.jpg',0)#0表示灰度图
# 第二步:进行数据类型转换
img_float32 = np.float32(img)#必须转换
# 第三步:使用cv2.dft进行傅里叶变化
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
# 第四步:使用np.fft.fftshift将低频转移到图像中心
dft_shift = np.fft.fftshift(dft)#将左上角的低频移动至中心
# 第五步:定义掩模:生成的掩模中间为1周围为0
rows, cols = img.shape
crow, ccol = int(rows/2), int(cols/2) #中心位置,方便确定掩膜
#高通滤波
mask = np.ones((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 0
# 第六步:将掩模与傅里叶变化后图像相乘,保留四周部分
fshift = dft_shift*mask
# 第七步:使用np.fft.ifftshift(将低频移动到原来的位置
f_ishift = np.fft.ifftshift(fshift)
# 第八步:使用cv2.idft进行傅里叶的反变化
img_back = cv2.idft(f_ishift)
# 第九步:使用cv2.magnitude转化为空间域内
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
# 第十步:进行绘图操作
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'),plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'),plt.xticks([]),plt.yticks([])
plt.show()
cv2.cornerHarris()
img:数据类型为float32的输入图像
blockSize:角点检测中指定区域的大小
ksize:Sobel求导中使用的窗口大小
k:取值参数为[0.04,0.06]
demo4:
import cv2
import numpy as np
img = cv2.imread('D:\\openCV_files\\data\\5\\chessboard.jpg')
print('img.shape:',img.shape)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#gray = np.float32(gray)
dst = cv2.cornerHarris(gray, 2, 3, 0.04) #block:2,ksize:3,k:0.04
print('dst.shape:', dst.shape)
img[dst>0.01*dst.max()] = [0,0,255] #把检测到的角点处用红色标记
cv2.imshow('dst',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
out4:
img.shape: (512, 512, 3)
dst.shape: (512, 512)
3.Scale Invariant Feature Transform(SIFT)
图像尺度空间
在一定的范围内,无论物体是大还是小,人眼都可以分辨出来,然而计算机要有相同的能力却很难,所以要让机器能够对物体在不同尺度下有一个统一的认知,就需要考虑图像在不同的尺度下都存在的特点。
import cv2
import numpy as np
img = cv2.imread('D:\\openCV_files\\data\\5\\test_1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
print(cv2.__version__) #查看opencv版本信息
#得到特征点
sift = cv2.SIFT_create() #opencv4.4.0以上版本重新支持了sift,调用方式由sift = cv2.xfeatures2d.SIFT_create()改为sift = cv2.SIFT_create()
kp = sift.detect(gray, None) #关键点信息
img = cv2.drawKeypoints(gray, kp, img) #绘制关键点
cv2.imshow('drawKeypoints', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#计算特征
kp, des = sift.compute(gray, kp) #返回关键点
print(np.array(kp).shape)
print(des.shape) #每个关键点被转换成128维的向量
print(des[0]) #取出来一个看看
out5:
4.5.3
(6809,)
(6809, 128)
[ 0. 0. 0. 0. 0. 0. 0. 0. 21. 8. 0. 0. 0. 0.
0. 0. 157. 31. 3. 1. 0. 0. 2. 63. 75. 7. 20. 35.
32. 74. 23. 66. 0. 0. 1. 3. 4. 1. 0. 0. 76. 15.
13. 27. 8. 1. 0. 2. 157. 112. 50. 31. 2. 0. 0. 9.
49. 42. 157. 157. 12. 4. 1. 5. 1. 13. 7. 12. 41. 5.
0. 0. 104. 8. 5. 19. 53. 5. 1. 21. 157. 55. 35. 90.
22. 0. 0. 17. 3. 6. 69. 157. 52. 0. 0. 0. 7. 33.
10. 10. 11. 0. 1. 6. 44. 9. 3. 7. 19. 5. 14. 26.
38. 28. 32. 92. 16. 2. 3. 4. 0. 0. 7. 92. 23. 0.
0. 0.]
4.特征匹配
demo6:
import cv2
img1 = cv2.imread('D:\\openCV_files\\data\\5\\box.png', 0)
img2 = cv2.imread('D:\\openCV_files\\data\\5\\box_in_scene.png', 0)
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
cv_show('img1', img1)
cv_show('img2', img2)
#Brute-Force蛮力匹配
sift = cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
#crossCheck表示两个特征点要相互匹配,例如A中的第i个特征点与B中的第j个特征点最近的,并且B中的第j个特征点到A中的第i个特征点也是
#NORM_L2:归一化数组的(欧几里德距离),如果其他特征计算方法需要考虑不同的匹配计算方式
bf = cv2.BFMatcher(crossCheck=True) #BFMatcher蛮力匹配
#1对1的匹配
matches = bf.match(des1, des2)
matches = sorted(matches, key=lambda x:x.distance)#排序
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=2) #把两幅图的关键点连在一起,取了前十个点
cv_show('img3',img3)
#k对最佳匹配
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2) #一个点可对应最近的两个点
good = []
for m,n in matches:
if m.distance < 0.75 * n.distance:
good.append([m])
img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good, None, flags = 2)
cv_show('img3',img3)
图像拼接代码:https://blog.csdn.net/weixin_45719141/article/details/119079973