一、在图像上绘制图形
import numpy as np
import matplotlib.pyplot as plt
import cv2 as cv
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 创建图像
img = np.zeros((512, 512, 3), np.uint8)
# 绘制图形
cv.line(img, (0, 0), (511, 511), (255, 0, 0), 5)
cv.circle(img, (256, 256), 60, (0, 0, 255), -1)
cv.rectangle(img, (100, 100), (400, 400), (0, 255, 0), 5)
cv.putText(img, "Hello", (70, 500), cv.FONT_HERSHEY_DUPLEX, 5, (255, 255, 255), 3)
# 显示结果
plt.imshow(img[:, :, ::-1])
plt.show()
二、获取一点像素值以及修改一点像素值
import numpy as np
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 创建10*10的图像
img = np.full((10, 10, 3), (0, 0, 0), np.uint8)
# 获取某一个点的像素值
px = img[5, 5]
print(px)
# 仅获取蓝色通道的强度值
blue = img[5, 5, 0]
print(blue)
# 修改某个位置的像素值
img[5, 5] = [0, 255, 0]
# 展示图像
plt.imshow(img[:, :, ::-1])
plt.show()
三、获取图片的大小
import cv2 as cv
# 导入图像
img = cv.imread('square.jpg')
shape = img.shape
t = img.dtype
size = img.size
print(shape, t, size)
四、通道的拆分与组合
import cv2 as cv
import matplotlib.pyplot as plt
# 导入图像
img = cv.imread('square.jpg')
# 通道拆分(显示b通道的灰度图)
b, g, r = cv.split(img)
plt.imshow(b, cmap=plt.cm.gray)
plt.show()
# 通道合并
img = cv.merge((b, g, r))
五、转换颜色空间:RGB→Gray和RGB→HSV
import cv2 as cv
import matplotlib.pyplot as plt
# 导入图像
img = cv.imread('square.jpg')
# 转换RGB→Gray
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
plt.imshow(gray, cmap=plt.cm.gray)
plt.show()
# 转换RGB→HSV
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
plt.imshow(hsv)
plt.show()
六、图像的算数运算
import cv2 as cv
import matplotlib.pyplot as plt
# 1、读取两张图像
square = cv.imread('square.jpg')
flag = cv.imread('flag.jpg')
# 2、两张图像分别用opencv加法和直接相加的的方法进行操作
img1 = cv.add(square, flag)
img2 = square + flag
# 3、图像显示
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(img1[:, :, ::-1])
axes[0].set_title("cv中的加法")
axes[1].imshow(img2[:, :, ::-1])
axes[1].set_title("直接相加")
plt.show()
七、图像的混合
import cv2 as cv
import matplotlib.pyplot as plt
# 1、读取两张图像
square = cv.imread('square.jpg')
flag = cv.imread('flag.jpg')
# 2、图像混合
img = cv.addWeighted(square, 0.7, flag, 0.3, 0)
# 3、图像显示
plt.figure(figsize=(8, 8))
plt.imshow(img[:, :, ::-1])
plt.show()
八、图像的缩放
'''API: cv.resize(src, dsize,fx=0,fy=0,interpolation=cv2.INTER_LINEAR
参数:
src:输入图像
dsize:绝对尺寸,直接是定调整后的图像大小
fx,fy:相对尺寸,将dsize设定为None,然后将fx和fy设定为比例因子即可
interpolation:插值方法,主要有以下四种:
cv2.INTER_LINEAR 双线性插值法
cv2.INTER_NEAREST 最近邻插值法
cv2.INTER_AREA 像素区域采样(默认)
cv2.INTER_CUBIC 双三次插值法'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1、导入图像
img = cv.imread('square.jpg')
# 2.图像缩放
# 2.1绝对尺寸
rows, cols = img.shape[:2]
res = cv.resize(img, (2*cols, 2*rows), interpolation=cv.INTER_CUBIC)
# 2.2相对尺寸
res1 = cv.resize(img, None, fx=0.5, fy=0.5)
# 3.图像显示
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(10, 8), dpi=100)
axes[0].imshow(res[:, :, ::-1])
axes[0].set_title("绝对尺寸(放大)")
axes[1].imshow(img[:, :, ::-1])
axes[1].set_title("原图")
axes[2].imshow(res1[:, :, ::-1])
axes[2].set_title("相对尺寸(缩小)")
plt.show()
九、图像平移
'''API: cv.warpAffine(img, M, dsize)
参数:
img:输入图像
M:2*3移动矩阵
对于(x,y)处的像素点,要把他移动到(x+tx,y+ty)处时,M矩阵应该如下设置:
M=[1,0,tx ;0,1,ty; ] 注意需要将M设置为np.float32类型的Numpy数组
dsize:输出图像大小 (宽度*高度)的形式
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1.输入图像
img = cv.imread('square.jpg')
# 2.图像平移
rows, cols = img.shape[:2]
M = M = np.float32([[1, 0, 500], [0, 1, 500]])
dst = cv.warpAffine(img, M, (cols, rows))
# 3.图像显示
fig, axes= plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(img[:, :, ::-1])
axes[0].set_title("原图")
axes[1].imshow(dst[:, :, ::-1])
axes[1].set_title("移动后的图像")
plt.show()
十、图像旋转
'''
API: cv2.getRotationMatrix2D(center, angle, scale)
参数:
center:旋转中心
angle:旋转角度
scale:缩放比例
返回:M:旋转矩阵
调用cv.warpAffine完成图像的旋转
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1.导入图像
img = cv.imread('square.jpg')
# 2.图像旋转
rows, cols = img.shape[:2]
# 2.1生成旋转矩阵
M = cv.getRotationMatrix2D((cols/2, rows/2), 90, 1)
# 2.2进行旋转变换
dst = cv.warpAffine(img, M, (cols, rows))
# 3图像展示
fig, axes=plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(img[:, :, ::-1])
axes[0].set_title("原图")
axes[1].imshow(dst[:, :, ::-1])
axes[1].set_title("旋转后的结果")
plt.show()
十一、仿射变化的矩阵
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1.图像读取
img = cv.imread('square.jpg')
# 2.仿射变换
rows, cols = img.shape[:2]
# 2.1创建变换矩阵
pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
pts2 = np.float32([[100, 100], [200, 50], [100, 250]])
M = cv.getAffineTransform(pts1, pts2)
# 2.2 完成仿射变换
dst = cv.warpAffine(img, M, (cols, rows))
# 3.图像展示
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(img[:, :, ::-1])
axes[0].set_title("原图")
axes[1].imshow(dst[:, :, ::-1])
axes[1].set_title("仿射后的图像")
plt.show()
十二、透射变换
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1.图像读取
img = cv.imread('square.jpg')
# 2.仿射变换
rows, cols = img.shape[:2]
# 2.1创建变换矩阵
pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])
pts2 = np.float32([[100, 145], [300, 100], [80, 290], [310, 310]])
T = cv.getPerspectiveTransform(pts1, pts2)
# 2.2 进行变换
dst = cv.warpPerspective(img, T, (cols, rows))
# 3.图像展示
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(img[:, :, ::-1])
axes[0].set_title("原图")
axes[1].imshow(dst[:, :, ::-1])
axes[1].set_title("透射后的图像")
plt.show()
十三、图像金字塔
'''
API:cv.pyrUp(img) #对图像进行上采样
cv.pyrDown(img) #对图像进行上采样
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1.图像读取
img = cv.imread('square.jpg')
# 2.对图像进行上采样
up_img = cv.pyrUp(img)
down_img = cv.pyrDown(img)
# 3.图像显示
cv.imshow('enlarge', up_img)
cv.imshow('original', img)
cv.imshow('shrink', down_img)
cv.waitKey(0)
cv.destroyAllWindows()
十四、连通性
'''
连通性的条件:1.两个像素位置相邻
2.两个像素的灰度值满足特定的相似性准则
腐蚀和膨胀
1.腐蚀
API: cv.erode(img, kernel, iterations)
参数:
img:要处理的图像
kernel:核结构
iterations:腐蚀的次数,默认为1
2.膨胀
API:cv.dilate(img, kernel, iterations)
参数:img:要处理的图像
kernel:核结构
iterations:腐蚀的次数
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1读取图像
img = cv.imread('square.jpg')
# 2创建核结构
kernel = np.ones((5, 5), np.uint8)
# 3图像的腐蚀与膨胀
erosion = cv.erode(img, kernel)
dilate = cv.dilate(img, kernel)
# 4图像展示
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(10, 8), dpi=100)
axes[0].imshow(img)
axes[0].set_title('原图')
axes[1].imshow(erosion)
axes[1].set_title('腐蚀后的图像')
axes[2].imshow(dilate)
axes[2].set_title('膨胀后的图像')
plt.show()
十五、开闭运算
'''
1.开运算:
定义:先腐蚀后膨胀
作用:分离物体,消除小区域
特点:消除噪点,去除小的干扰块,而不影响原来的图像
2.闭运算
定义:先膨胀后腐蚀
作用:消除/“闭合”物体里面的孔洞
特点:可以填充闭合区域
API:
cv.morphologyEx(img, op, kernel)
参数:
img:要处理的图像
op:处理的方式:若进行开运算,则设为cv.MORPH_OPEN
若进行闭运算,则设为cv.MORPH_CLOSE
kernel:核结构
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1导入图像
img1 = cv.imread('square.jpg')
img2 = cv.imread('flag.jpg')
# 2创建核结构
kernel = np.ones((10, 10), np.uint8)
# 3图像的开闭
cvOpen = cv.morphologyEx(img1, cv.MORPH_OPEN, kernel)
cvClose = cv.morphologyEx(img2, cv.MORPH_CLOSE, kernel)
# 4图像展示
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8))
axes[0, 0].imshow(img1)
axes[0, 0].set_title("原图")
axes[0, 1].imshow(cvOpen)
axes[0, 1].set_title("开运算结果")
axes[1, 0].imshow(img2)
axes[1, 0].set_title("原图")
axes[1, 1].imshow(cvClose)
axes[1, 1].set_title("闭运算结果")
plt.show()
十六、礼帽和黑帽
'''
1.礼帽运算
原图像与开运算结果图之差
公式:dst= tophat(src,element)=src- open(src,element)
2.黑帽运算
闭运算的结果图与原图像之差
公式:dst= blackhat(src,element)= close(src,element)-src
API: cv.morphologyEx(img, op, kernel)
参数:
img:处理的图像
op:处理方式
cv.MORPH_CLOSE 闭运算
cv.MORPH_OPEN 开运算
cv.MORPH_TOPHAT 礼帽运算
cv.MORPH_BLACKHAT 黑帽运算
kernel:核结构
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1导入图像
img1 = cv.imread('square.jpg')
img2 = cv.imread('flag.jpg')
# 2创建核结构
kernel = np.ones((10, 10), np.uint8)
# 3图像的礼帽与黑帽运算
cvOpen = cv.morphologyEx(img1, cv.MORPH_TOPHAT, kernel)
cvClose = cv.morphologyEx(img2, cv.MORPH_BLACKHAT, kernel)
# 4图像展示
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8))
axes[0, 0].imshow(img1)
axes[0, 0].set_title("原图")
axes[0, 1].imshow(cvOpen)
axes[0, 1].set_title("礼帽结果")
axes[1, 0].imshow(img2)
axes[1, 0].set_title("原图")
axes[1, 1].imshow(cvClose)
axes[1, 1].set_title("黑帽结果")
plt.show()
十七、均值滤波
'''
优点:算法简单,计算速度快
缺点:去噪的同时会去除很多细节部分,将图像变得模糊
API: cv.blur(src, ksize, anchor, borderType)
参数:src:输入图像
ksize:卷积核的大小
anchor:默认值(-1, -1),表示核中心
borderType:边界类型
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1.导入图像
img = cv.imread('square.jpg')
# 2.均值滤波
blur = cv.blur(img, (5, 5))
# 3.图像显示
plt.figure(figsize=(10, 8), dpi=100)
plt.subplot(121), plt.imshow(img[:, :, ::-1]), plt.title("原图")
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur[:, :, ::-1]),plt.title("均值滤波之后的结果")
plt.xticks([]), plt.yticks([])
plt.show()
十八、高斯滤波
'''
API: cv.GaussianBlur(src, ksize, sigmaX, sigmay, borderType)
参数:
src:输入图像
ksize:高斯卷积核大小,注意:卷积核的宽度和高度都应该是奇数,且可以不同
sigmaX:水平方向的标准差
sigmaY:垂直方向的标准差,默认为0,表示与sigmaX相同
borderType:填充边界类型
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
img = cv.imread('square.jpg')
blur = cv.GaussianBlur(img, (3, 3), 1)
plt.figure(figsize=(10, 8), dpi=100)
plt.subplot(121), plt.imshow(img[:, :, ::-1]), plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur[:, :, ::-1]), plt.title('高斯滤波之后的图像')
plt.xticks([]), plt.yticks([])
plt.show()
十九、中值滤波
'''
API: cv.medianBlur(src, ksize)
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1.导入图像
img = cv.imread('square.jpg')
# 2.中值滤波
blur = cv.medianBlur(img, 5)
# 3.图像显示
plt.figure(figsize=(10, 8), dpi=100)
plt.subplot(121), plt.imshow(img[:, :, ::-1]), plt.title("原图")
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur[:, :, ::-1]), plt.title("中值滤波之后的结果")
plt.xticks([]), plt.yticks([])
plt.show()
二十、灰度直方图
'''
API: cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
参数:
images:原图。当传入函数时应该用中括号[]括起来
Channels:如果输入的是灰度图,他的值就是[0],如果是彩色的话,传入的参数可以是[0],[1],[2]它们分别对应着通道BGR
mask:掩膜图像。要统计整幅直方图就把他设置为None。统计某一部分的话需要制作一个研掩膜图像
histSize:BIN的数目,用[]括起来
ranges:像素值范围,通常为[0, 256]
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 1.导入图像
img = cv.imread('square.jpg', 0)
# 2.统计灰度图
histr = cv.calcHist([img], [0], None, [256], [0, 256])
plt.figure(figsize=(10, 6), dpi=100)
plt.plot(histr)
plt.grid()
plt.show()
二十一、掩膜的应用
'''
掩膜是由0和1组成的一个二进制图像。通常使用二维矩阵数组进行。其中1值区域被处理,0值区域被屏蔽
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
img = cv.imread('square.jpg', 0)
# 创建蒙版
mask = np.zeros(img.shape[:2], np.uint8)
mask[400:1650, 200:1500] = 255
# 掩膜
masked_img = cv.bitwise_and(img, img, mask=mask)
# 统计掩膜后图像的灰度图
mask_histr = cv.calcHist([img], [0], mask, [256], [1, 256])
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8))
axes[0, 0].imshow(img, cmap=plt.cm.gray)
axes[0, 0].set_title('原图')
axes[0, 1].imshow(mask, cmap=plt.cm.gray)
axes[0, 1].set_title('蒙版数据')
axes[1, 0].imshow(masked_img, cmap=plt.cm.gray)
axes[1, 0].set_title('掩膜后数据')
axes[1, 1].plot(mask_histr)
axes[1, 1].grid()
axes[1, 1].set_title('灰度直方图')
plt.show()
二十二、直方图均衡化
'''
API: dst = cv.equalizeHist(img)
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
img = cv.imread('square.jpg', 0)
dst = cv.equalizeHist(img)
fig, axes= plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(img, cmap=plt.cm.gray)
axes[0].set_title('原图')
axes[1].imshow(dst, cmap=plt.cm.gray)
axes[1].set_title('均衡化后的结果')
plt.show()
二十三、自适应的直方图均衡化
'''
整幅图像会被分成很多小块,这些小块被称为“tiles”(默认大小为8*8)。然后对每一小块分别进行直方图均衡化
API : cv.createCLAHE(clipLimit, tileGridSize)
参数:
clipLimit:对比度限制,默认为40
tileGridSize:分块的大小,默认为8*8
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
img = cv.imread('square.jpg', 0)
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
cl1 = clahe.apply(img)
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 8), dpi=100)
axes[0].imshow(img, cmap=plt.cm.gray)
axes[0].set_title('原图')
axes[1].imshow(cl1, cmap=plt.cm.gray)
axes[1].set_title('自适应均衡化之后的结果')
plt.show()
二十四、边缘检测(Sobel检测算子)
'''
(1)Sobel检测算子
API:Sobel_x_or_y = cv2.Sobel(src, ddepth, dx, dy, dst, ksize, scale, delta, borderType)
参数:
src:传入的图像
ddepth:图像的深度
dx和dy:只求导的阶数,0表示在这个方向上没有求导,取值为0,、1
ksize:是Sobel算子的大小,即卷积核的大小,必须为奇数,默认为3
scale:缩放导数的比例常数,默认情况下没有伸缩系数
borderType:图像边界的模式,默认为cv2.BORDER_DEFAULT
注意:Sobel函数求完导数之后会有负值,还会有大于255的值,而原图像是uint8,即8位无符号数,所有Sobel建立的图像位数不够,会有截断
现象。因此要使用16位有符号的数据类型,即cv2.CV_16S。处理完成后,再使用cv2.convertScaleAbs()函数将其转换成原来的uint8格式,否则无法显示
Sobel算子是在两个方向上计算的,最后还需要用cv2.addWeighted()函数将其组合起来
Scale_abs = cv2.convertScaleAbs(x)
result = cv2.addWeighted(src1, alpha, src2,beta)
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
img = cv.imread('square.jpg', 0)
# 计算Sobel卷积结果
x = cv.Sobel(img, cv.CV_16S, 1, 0)
y = cv.Sobel(img, cv.CV_16S, 0, 1)
# 将数据进行转换
Scale_absX = cv.convertScaleAbs(x)
Scale_absY = cv.convertScaleAbs(y)
# 结果合成
result = cv.addWeighted(Scale_absX, 0.5, Scale_absY, 0.5, 0)
# 图像显示
plt.figure(figsize=(10, 8), dpi=80)
plt.subplot(121), plt.imshow(img, cmap=plt.cm.gray), plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(result, cmap=plt.cm.gray), plt.title('Sobel滤波之后的结果')
plt.xticks([]), plt.yticks([])
plt.show()
二十五、 边缘检测(Laplacian算子)
'''
(2)Laplacian算子
拉普拉斯算子,用二阶导数
API: laplacian = cv2.Laplacian(src, ddepth[, dst[,ksize[, scale[, delta[, borderType]]]]])
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
img = cv.imread('square.jpg', 0)
# laplacian转换
result = cv.Laplacian(img, cv.CV_16S)
Scale_abs = cv.convertScaleAbs(result)
# 图像显示
plt.figure(figsize=(10, 8), dpi=80)
plt.subplot(121), plt.imshow(img, cmap=plt.cm.gray), plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(Scale_abs, cmap=plt.cm.gray), plt.title('Laplacian检测之后的结果')
plt.xticks([]), plt.yticks([])
plt.show()
二十六、边缘检测(Canny检测)
'''
(3)Canny检测
API: canny = cv2.Canny(image, threshold1, threshold2)
参数:
image:灰度图
threshold1:minval,较小的阈值将间断的边缘连接起来
threshold2:maxval,较大的阈值检测图像中明显的边缘
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
img = cv.imread('square.jpg', 0)
# Canny边缘检测
lowThreshold = 0
max_lowThreshold = 100
canny = cv.Canny(img, lowThreshold, max_lowThreshold)
# 图像显示
plt.figure(figsize=(10, 8), dpi=80)
plt.subplot(121), plt.imshow(img, cmap=plt.cm.gray), plt.title('原图')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(canny, cmap=plt.cm.gray), plt.title('Canny检测之后的结果')
plt.xticks([]), plt.yticks([])
plt.show()
二十七、模板匹配
'''
定义:在给定的图片中查找和模板最相似的区域
API:res = cv.matchTemplate(img, template, method)
参数:img:要进行模板匹配的图像
Template:模板
method:实现模板匹配的算法,主要有
1、平方差匹配(CV_TM_SQDIFF):主要利用模板与图像之间的平方差进行匹配,最好的匹配是0,匹配越差,匹配的值越大
2、相关匹配(CV_TM_CCORR):利用模板与图像之间的乘法进行匹配,数值越大表示匹配程度越高,反之匹配程度较小
3、利用相关系数匹配(CV_TM_CCOEFF):利用模板与图像之间的相关系数匹配,1表示完美的匹配,-1表示最差的匹配
匹配完成后,使用cv.minMaxLoc()方法查找最大值所在的位置即可。如果要使用平方差作为比较方法,则最小位置是最佳匹配位置
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
img = cv.imread('square.jpg')
template = cv.imread('square_template.jpg')
h, w, l = template.shape
# 模板匹配
res = cv.matchTemplate(img, template, cv.TM_CCORR)
# 返回图像中最匹配的位置,确定左上角的坐标,并将匹配位置绘制在图像上
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv.rectangle(img, top_left, bottom_right, (0, 0, 0), 2)
# 图像显示
plt.imshow(img[:, :, ::-1])
plt.title('匹配结果'), plt.xticks([]), plt.yticks([])
plt.show()
二十八、霍夫变换
'''
定义:用来提取图像中的直线和圆等几何形状
1、霍夫线变换
在笛卡尔坐标系中一条直线由两个点确定
笛卡尔坐标系中的一条直线,对应于霍夫空间中的一个点
API:cv.HoughLines(img, rho, theta, threshold)
参数:
img:检测的图像,要求是二值化的图像,所以在调用霍夫变换之前首先要进行二值化,或者进行Canny边缘检测
rho、theta:ρ和θ的精确度
threshold::阈值,只有累加器中的值高于该阈值时才被认为是直线
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
img = cv.imread('line.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray, 50, 150)
# 霍夫直线变换
lines = cv.HoughLines(edges, 0.8, np.pi / 180, 150)
# 将检测的线绘制在图像上
for line in lines:
rho, theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
x1 = int(x0 + 1000 * (-b))
y1 = int(y0 + 1000 * (a))
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * (a))
cv.line(img, (x1, y1), (x2, y2), (0, 255, 0))
plt.figure(figsize=(10, 8), dpi=100)
plt.imshow(img[:, :, ::-1]), plt.title('霍夫变换线检测')
plt.xticks([]), plt.yticks([])
plt.show()
'''
霍夫圆变换
API:circles = cv.HoughCircles(img, method, dp, minDist, param1=100, param2=100, minRadius=0, maxRadius=0)
参数:
img:输入图像
method:使用霍夫变换圆检测的算法,他的参数是CV_HOUGH_GRASIENT
dp: 霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一半
minDist:为圆心之间的最小距离,如果检测到两个圆心之间距离小于该值,则认为它们是同一个圆心
param1:边缘检测时使用Canny算子的高阈值,低阈值时高阈值的一半
param2:检测圆心和确定半径时所共有的阈值
minRadius和maxRadius为所检测到的圆半径的最小值与最大值
返回:
circles:输出圆向量,包括三个浮点型的元素——圆心横坐标,圆心纵坐标和圆半径
由于霍夫圆检测对噪声比较敏感,所以首先对图像进行中值滤波
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
planets = cv.imread('line.jpg')
gay_img = cv.cvtColor(planets, cv.COLOR_BGRA2GRAY)
# 进行中值模糊
img = cv.medianBlur(gay_img, 7)
# 霍夫圆检测
circles = cv.HoughCircles(img, cv.HOUGH_GRADIENT, 1, 200, param1=100, param2=30, minRadius=0, maxRadius=100)
for i in circles[0, :]:
cv.circle(planets, (i[0], i[1]), i[2], (0, 255, 0), 2)
cv.circle(planets, (i[0], i[1]), 2, (0, 0, 255), 3)
plt.figure(figsize=(10, 8), dpi=100)
plt.imshow(planets[:, :, ::-1]), plt.title('霍夫变换圆检测')
plt.xticks([]), plt.yticks([])
plt.imshow()
二十九、角点特征
'''
1、Harris角点检测
思想:通过图像的局部的小窗口观察图像,角点的特征是窗口沿任意方向移动都会导致图像灰度的明显变化
API : dst = cv.cornerHarris(src, blockSize, ksize, k)
参数:
img:数据类型为float32的输入图像
blockSize:角点检测中要考虑的邻域大小
kszie:sobel求导使用的核大小
k:角点检测方程中的自由参数,取值为[0.04, 0.06]
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
img = cv.imread('square.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 角点检测
gray = np.float32(gray)
dst = cv.cornerHarris(gray, 2, 3, 0.04)
img[dst>0.001*dst.max()] = [0, 0, 225]
plt.figure(figsize=(10, 8), dpi=100)
plt.imshow(img[:, :, ::-1]), plt.title('Harris角点检测')
plt.xticks([]), plt.yticks([])
plt.show()
'''
2、Shi-Tomasi角点检测
API : corners = cv2.goodFeaturesToTrack(image, maxcorners, qualityLevel, minDistance)
参数:
Image:输入灰度图像
maxCorners:获取角点数的数目
qualityLevel:该参数指出最低可接受的角点质量水平。在0-1之间
minDistance:角点之间最小的欧式距离,避免得到相邻的特征点
返回:
corners:搜索到的角点,在这里所有低于质量水平的角点被排除掉,然后把合格的角点按质量排序,然后将质量较好的角点附近(小于最小欧氏距离)的角点删掉,最后找到maxcorners个角点返回
'''
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from pylab import mpl
# matpltotlib 绘图时正常显示字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
img = cv.imread('line.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
corners = cv.goodFeaturesToTrack(gray, 10, 0.02, 20)
for i in corners:
x, y = i.ravel()
cv.circle(img, (x, y), 2, (0, 0, 255), -1)
plt.figure(figsize=(10, 8), dpi=100)
plt.imshow(img[:, :, ::-1]), plt.title('Shi-Tomasi角点检测')
plt.xticks([]), plt.yticks([])
plt.show()
三十、SIFT算法
'''
分解为四步:
1、尺度空间极值检测:搜索所有尺度上的图像位置。通过高斯差分函数来识别潜在的对于尺度和旋转不变的关键点
2、关键点定位:在每一个候选的位置上,通过一个拟合精细的模型来确定位置和尺度。关键点的选择依据于他们的稳定程度
3、关键点方向确定:基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向。所有后面的对图像的数据操作 都相对于关键点的
方向、尺度和位置进行变换,从而保证了对于这些变换的不变性。
4、关键点描述:在每个关键点周围的邻域内,在选定的尺度上测量图像局部的梯度。这些梯度作为关键点的描述符,它允许比较大的局部形状的变形或者光照的变化
改进:SURF算法
计算量小,运算速度快
代码实现SIFT算法
1、实例化sift
sift = cv.xfeatures2d.SIFT_create()
2、利用sift.detectAndCompute()检测关键点并计算
kp, des = sift.detectAndCompute(gray,None)
参数:
gray:进行关键点检测的图像,要用灰度图像
返回:
kp:关键点信息,包括位置,尺度,方向信息
des:关键点描述符,每个关键点对应128个梯度信息的特征向量
3、将关键点检测结果绘制在图像上
cv.drawKeypoints(image, keypoints, outputimage, color, flags)
参数:
Image:原始图像
keypoints:关键点信息,将其绘制在图像上
outputimage:输出图片,可以是原始图像
color:颜色设置,通过修改RGB的值
flags:绘图功能的标识设置
①cv2.DRAW_MATCHES_FLAGS_DEFAULT:创建输出图像矩阵,使用现存的输出图像绘制匹配对和特征点,对每一个关键点只绘制中间点
②cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG:不创建输出图像,而是在输出图像上绘制匹配对
③cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS:对每一个特征点绘制带大小和方向的关键点图形
④cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS:单点的特征点不被绘制
'''
img = cv.imread('square.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
sift = cv.SIFT_create()
kp, des = sift.detectAndCompute(gray, None)
cv.drawKeypoints(img, kp, img, flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
plt.figure(figsize=(10, 8), dpi=100)
plt.imshow(img[:, :, ::-1]), plt.title('sift检测')
plt.xticks([]), plt.yticks([])
plt.show()