OpenCV计算机视觉库
计算机视觉和图像处理
- Tensorflow入门
- 深度神经网络
- 图像分类
- 目标检测
- 图像分割
- OpenCV
- Pytorch
- NLP自然语言处理
OpenCV
- 一、OpenCV简介
- 1.1 简介
- 1.2 OpenCV部署
- 1.3 OpenCV模块
- 二、OpenCV基本操作
- 2.1 图像的基本操作
- 2.1.1 图像的IO操作
- 2.1.2 绘制几何图像
- 2.1.3 获取并修改图像的像素点
- 2.1.4 获取图像的属性
- 2.1.5 图像通道的拆分和合并
- 2.1.6 色彩空间的改变
- 2.2 算数操作
- 2.2.1 图像的加法
- 2.2.2 图像的混合
- 三、OpenCV图像处理
- 3.1 图像的几何变换
- 3.2 图像的形态学操作
- 3.3 图像的平滑
- 3.4 直方图
- 3.1.4 灰度直方图
- 3.1.5 直方图均衡化
- 3.5 边缘检测
- 3.5.1 Sobel检测算子
- 3.5.2 Laplacian算子
- 3.5.3 Canny边缘检测
- 3.6 模板匹配和霍夫变换的应用
- 3.6.1 模板匹配
- 3.6.2 霍夫变换
- 3.7 图像变化
- 3.7.1 傅里叶变换
- 3.7.2 高通和低通滤波
- 3.7.3 带通和带阻滤波
- 3.8 轮廓检测与轮廓特征
- 3.8.1 轮廓检测
- 3.8.2 轮廓特征
- 3.9 图像分割
- 3.9.1 全阈值分割
- 3.9.2 自适应阈值分割
- 3.9.3 Ostu阈值(大律法)
- 3.9.4 分水岭算法
- 3.9.5 GrabCut算法
- 四、图像的特征提取与描述
- 4.1 Harris角点检测
- 4.2 Shi-Tomasi角点检测
- 4.3 sift算法
- 4.4 fast检测算法
- 4.5 orb角点检测
- 五、视频操作
- 5.1 视频读写
- 5.2 视频保存
- 5.3 视频追踪
- 5.3.1 meanshift算法
- 5.3.2 camshift算法
- 六、人脸、眼睛检测案例
- 6.1 人脸以及眼睛检测(图片)
- 6.2 人脸以及眼睛检测(视频)
一、OpenCV简介
1.1 简介
OpenCV是⼀个计算机视觉处理开源软件库,⽀持与计算机视觉和机器学习相关的众多算法。
1.2 OpenCV部署
- 创建虚拟环境
在Anaconda终端中创建虚拟环境OpenCV_env
conda create --name OpenCV_env
- 激活虚拟环境
conda activate OpenCV_env
- 安装OpenCV
安装OpenCV之前需要先安装numpy, matplotlib
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
如果我们要利用SIFT和SURF算法进行特征提取时,还需安装:
pip install opencv-contrib-python -i https://pypi.tuna.tsinghua.edu.cn/simple
- 查看是否安装成功
import cv2
cv2.__version__
1.3 OpenCV模块
core
模块实现了最核心的数据结构及其基本运算,如绘图函数、数组操作相关函数等。highgui
模块实现了视频与图像的读取、显示、存储等接口。imgproc
模块实现了图像处理的基础方法,包括图像滤波、图像的几何变换、平滑、阈值分割、形态学处理、边缘检测、目标检测、运动分析和对象跟踪等。features2d
模块用于提取图像特征以及特征匹配,nonfree模块实现了一些专利算法,如sift特征。objdetect
模块实现了一些目标检测的功能,经典的基于Haar、LBP特征的人脸检测,基于HOG的行人、汽车等目标检测,分类器使用CascadeClassification(级联分类)和Latent SVM等。
二、OpenCV基本操作
2.1 图像的基本操作
2.1.1 图像的IO操作
# 读取图像
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt#以灰度图的方式读取图像
img = cv.imread("dog.jpg",0)
# 显示图像
# Jupyter Notebook 是一个基于 Web 的交互式计算环境,不支持传统的 GUI 窗口显示
# cv.imshow('image',img)
# cv.waitKey(0)
plt.imshow(img,cmap='gray')
# 以彩色图的方式读取图像
img1 = cv.imread("dog.jpg",1)
# img1[:,:,::-1]将BGR图像转换为RGB图像
plt.imshow(img1[:,:,::-1])
使用cv.imread()读取的图像是BGR,而matplot使用是的RGB图像
img.shape
# 图像保存
cv.imwrite('dog1.jpg',img)
2.1.2 绘制几何图像
# 创建图像
img = np.zeros((512,512,3),np.uint8)
# 直线的起点、终点、颜色、宽度
cv.line(img,(0,0),(512,512),(255,0,0),5)
# 圆形的圆心、半径、颜色、填充、宽度
cv.circle(img,(250,250),130,(0,255,0),-1,5)
# 矩形的左上角、右下角、颜色、宽度
cv.rectangle(img,(50,50),(450,450),(0,0,255),5)
# 图像中添加文字 文本、位置、字体、字体大小、颜色、宽度
cv.putText(img,"OpenCV",(130,250),cv.FONT_HERSHEY_COMPLEX,2,(255,0,255),2)
plt.imshow(img[:,:,::-1])
plt.show()
2.1.3 获取并修改图像的像素点
img2 = np.zeros((250,250,3),np.uint8)
plt.imshow(img2[:,:,::-1])
# 获取位置(50,200)的像素点
img2[50,200]
#获取位置(50,100)蓝色通道的强度值,0表示蓝色,1表示绿色,2表示红色
img2[50,100,0]
# 修改位置(50,100)的像素值
img2[50,100] = [255,0,0]
plt.imshow(img2[:,:,::-1])
2.1.4 获取图像的属性
img2.shape
img2.size
img2.dtype
2.1.5 图像通道的拆分和合并
# 通道拆分
b,g,r = cv.split(img1)
plt.imshow(b,cmap='gray')
# 通道合并
img3 = cv.merge((b,g,r))
plt.imshow(img3[:,:,::-1])
2.1.6 色彩空间的改变
# 将BGR通道图像转变为HSV通道图像
img3 = cv.cvtColor(img1,cv.COLOR_BGR2HSV)
plt.imshow(img3[:,:,::-1])
# 将BGR通道图像变为GRAY通道图像
img4 = cv.cvtColor(img1,cv.COLOR_BGR2GRAY)
plt.imshow(img4,cmap='gray')
2.2 算数操作
2.2.1 图像的加法
# 读取图像
img_sun = cv.imread('sun.jpg')
img_tree = cv.imread('tree.jpg')
plt.imshow(img_tree[:,:,::-1])
plt.imshow(img_sun[:,:,::-1])
# 查看图像形状
img_sun.shape,img_tree.shape
形状相同才能进行相加
# 缩小图形形状
img_sun = cv.resize(img_sun,(350,251))
img_sun.shape
# 加法操作
img_cvadd = cv.add(img_sun,img_tree)
img_add = img_sun+img_tree
fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(img_cvadd[:,:,::-1])
axes[0].set_title("cv中的加法")
axes[1].imshow(img_add[:,:,::-1])
axes[1].set_title("直接相加")
plt.show()
2.2.2 图像的混合
# 读取图像
img_sun = cv.imread('sun.jpg')
img_tree = cv.imread('tree.jpg')# 缩小图形形状
img_sun = cv.resize(img_sun,(350,251))# 图像混合,gamma参数会影响最终图像的亮度
img5 = cv.addWeighted(img_sun,0.3,img_tree,0.7,0)# 图像的显示
plt.imshow(img5[:,:,::-1])
plt.show()
三、OpenCV图像处理
3.1 图像的几何变换
import cv2 as cv
import matplotlib.pyplot as plt
- 图像缩放
# 读取图片
img = cv.imread('dog.jpg')# 图像缩放
# 绝对尺寸
rows,cols = img.shape[:2]
res = cv.resize(img,(2*cols,2*rows))
# 相对尺寸
res1 = cv.resize(img,None,fx=0.5,fy=0.5)# 图像显示
fig,axes = plt.subplots(1,3,figsize=(10,8))
axes[0].imshow(img[:,:,::-1])
axes[0].set_title("原始图像")
axes[1].imshow(res[:,:,::-1])
axes[1].set_title("绝对尺寸")
axes[2].imshow(res1[:,:,::-1])
axes[2].set_title("相对尺寸")
plt.show()
- 图像平移
import numpy as npimg = cv.imread('dog.jpg')# 像素点平移(50,100)
rows,cols = img.shape[:2]
# 平移矩阵
m = np.float32([[1,0,50],[0,1,100]])
res = cv.warpAffine(img,m,(cols,rows))fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(img[:,:,::-1])
axes[0].set_title("原始图像")
axes[1].imshow(res[:,:,::-1])
axes[1].set_title("平移后图像")
plt.show()
- 图像旋转
img = cv.imread("dog.jpg")rows,cols = img.shape[:2]
# 旋转矩阵
m = cv.getRotationMatrix2D((cols//2,rows//2),90,0.5)
res = cv.warpAffine(img,m,(cols,rows))fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(img[:,:,::-1])
axes[0].set_title("原始图像")
axes[1].imshow(res[:,:,::-1])
axes[1].set_title("旋转后图像")
plt.show()
- 仿射变换
rows,cols = img.shape[:2]
# 原点集
pts1 = np.float32([[50,50],[200,50],[50,200]])
# 目标点集
pts2 = np.float32([[100,100],[200,50],[100,250]])
# 仿射变化矩阵
m = cv.getAffineTransform(pts1,pts2)res = cv.warpAffine(img,m,(cols,rows))fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(img[:,:,::-1])
axes[0].set_title("原始图像")
axes[1].imshow(res[:,:,::-1])
axes[1].set_title("仿射后图像")
plt.show()
- 投射变换
img = cv.imread("dog.jpg")rows,cols = img.shape[:2]
# 投射变换矩阵
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[100,145],[300,100],[80,290],[310,300]])
m = cv.getPerspectiveTransform(pts1,pts2)
# 进行变换
res = cv.warpPerspective(img,m,(cols,rows))fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(img[:,:,::-1])
axes[0].set_title("原图像")
axes[1].imshow(res[:,:,::-1])
axes[1].set_title("仿射后图像")
plt.show()
- 图像金字塔
img = cv.imread("dog.jpg")# 上采样
img_up = cv.pyrUp(img)
# 下采样
img_down = cv.pyrDown(img)fig,axes = plt.subplots(1,3,figsize=(10,8))
axes[0].imshow(img[:,:,::-1])
axes[0].set_title("原图像")
axes[1].imshow(img_up[:,:,::-1])
axes[1].set_title("上采样图像")
axes[2].imshow(img_down[:,:,::-1])
axes[2].set_title("下采样图像")
plt.show()
3.2 图像的形态学操作
- 膨胀和腐蚀
img = cv.imread("img_five.jpg")# 创建核结构
kernel = np.ones((5,5),np.uint8)# 腐蚀
erode = cv.erode(img,kernel)
# 膨胀
dilate = cv.dilate(img,kernel)fig,axes = plt.subplots(1,3,figsize=(10,8))
axes[0].imshow(img[:,:,::-1])
axes[0].set_title("原图像")
axes[1].imshow(erode[:,:,::-1])
axes[1].set_title("腐蚀后图像")
axes[2].imshow(dilate[:,:,::-1])
axes[2].set_title("膨胀后图像")
plt.show()
- 开闭运算
img_1 = cv.imread('img1.png')
img_2 = cv.imread('img2.png')kernel = np.ones((10,10),np.uint8)
Open = cv.morphologyEx(img_1,cv.MORPH_OPEN,kernel)
Close = cv.morphologyEx(img_2,cv.MORPH_CLOSE,kernel)fig,axes = plt.subplots(2,2,figsize=(10,8))
axes[0][0].imshow(img_1[:,:,::-1])
axes[0][0].set_title("原图像")
axes[0,1].imshow(Open[:,:,::-1])
axes[0,1].set_title("开运算图像")
axes[1,0].imshow(img_2[:,:,::-1])
axes[1,0].set_title("原图像")
axes[1,1].imshow(Close[:,:,::-1])
axes[1,1].set_title("闭运算图像")
plt.show()
- 礼貌和黑帽
img_1 = cv.imread("img1.png")
img_2 = cv.imread("img2.png")kernel = np.ones((10,10),np.uint8)
Open = cv.morphologyEx(img_1,cv.MORPH_TOPHAT,kernel)
Close = cv.morphologyEx(img_2,cv.MORPH_BLACKHAT,kernel)fig,axes = plt.subplots(2,2,figsize=(10,8))
axes[0][0].imshow(img_1[:,:,::-1])
axes[0][0].set_title("原图像")
axes[0,1].imshow(Open[:,:,::-1])
axes[0,1].set_title("礼帽运算结果")
axes[1,0].imshow(img_2[:,:,::-1])
axes[1,0].set_title("原图像")
axes[1,1].imshow(Close[:,:,::-1])
axes[1,1].set_title("黑帽运算结果")
plt.show()
3.3 图像的平滑
img_girl= cv.imread("girl_img.png")# 均值滤波
blur = cv.blur(img_girl,(7,7))
# 高斯滤波
gaublur = cv.GaussianBlur(img_girl,(9,9),0)
# 中值滤波
medblur = cv.medianBlur(img_girl,5)fig,axes = plt.subplots(2,2,figsize=(10,8))
axes[0][0].imshow(img_girl[:,:,::-1])
axes[0][0].set_title("原图像")
axes[0,1].imshow(blur[:,:,::-1])
axes[0,1].set_title("均值滤波运算结果")
axes[1,0].imshow(gaublur[:,:,::-1])
axes[1,0].set_title("高斯滤波结果")
axes[1,1].imshow(medblur[:,:,::-1])
axes[1,1].set_title("中值滤波结果")
plt.show()
3.4 直方图
3.1.4 灰度直方图
- 直方图的计算和绘制
img_dog = cv.imread("dog.jpg",0)# 统计灰度图
histr = cv.calcHist(img_dog,[0],None,[256],[0,256])fig,axes = plt.subplots(1,2,figsize=(18,6))
axes[0].imshow(img_dog,cmap='gray')
axes[1].plot(histr)
axes[1].grid()
axes[1].set_xlabel('Pixel Value')
axes[1].set_ylabel('Frequency')
# 调整布局
plt.tight_layout()
plt.show()
- 掩码的应用
img_dog1 = cv.imread("dog.jpg",0)# 创建遮挡
mask = np.zeros(img_dog1.shape[:2],np.uint8)
mask[50:130,150:230] = 255# 进行按位与运算
mask_img = cv.bitwise_and(img_dog1,img_dog1,mask=mask)mask_histr = cv.calcHist([img_dog1],[0],mask,[256],[0,256])fig,axes = plt.subplots(2,2,figsize=(10,8))
axes[0,0].imshow(img_dog1,cmap='gray')
axes[0,0].set_title("原图")
axes[0,1].imshow(mask,cmap='gray')
axes[0,1].set_title("遮挡")
axes[1,0].imshow(mask_img,cmap="gray")
axes[1,0].set_title("遮挡后数据")
axes[1,1].plot(mask_histr)
axes[1,1].set_title("灰度直方图")
plt.show()
3.1.5 直方图均衡化
- 应用
img_dog = cv.imread("dog.jpg",0)dst = cv.equalizeHist(img_dog)fig,axes = plt.subplots(1,2,figsize=(18,6))
axes[0].imshow(img_dog,cmap='gray')
axes[0].set_title("原图")
axes[1].imshow(dst,cmap='gray')
axes[1].set_title("均衡化后的结果")
# plt.tight_layout()
plt.show()
- 自适应的直方图均衡化
img_dog = cv.imread("dog.jpg",0)clahe = cv.createCLAHE(clipLimit=2,tileGridSize=(12,12))
cl1 = clahe.apply(img_dog)fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(img_dog,cmap="gray")
axes[0].set_title("原图")
axes[1].imshow(cl1,cmap="gray")
axes[1].set_title("自适应后图像")
plt.show()
3.5 边缘检测
3.5.1 Sobel检测算子
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
img_horse = cv.imread("horse.jpg",0)# 计算Sobel卷积结果(边缘检测)
x = cv.Sobel(img_horse,cv.CV_16S,1,0)
y = cv.Sobel(img_horse,cv.CV_16S,0,1)# 数据转换(将其缩放到uint8)
scale_x = cv.convertScaleAbs(x)
scale_y = cv.convertScaleAbs(y)# 结果合成 gamma为正亮度增加,0亮度不变,负数亮度降低
res = cv.addWeighted(scale_x,0.5,scale_y,0.5,0)fig,axes = plt.subplots(1,2,figsize=(9,10))
axes[0].imshow(img_horse,cmap='gray')
axes[0].set_title("原图")
axes[1].imshow(res,cmap=plt.cm.gray)
axes[1].set_title("Sobel滤波后结果")
plt.show()
# ksize为-1时,使用3x3的Scharr滤波器
x = cv.Sobel(img_horse,cv.CV_16S,1,0,ksize=-1)
y = cv.Sobel(img_horse,cv.CV_16S,0,1,ksize=-1)scale_x = cv.convertScaleAbs(x)
scale_y = cv.convertScaleAbs(y)
res = cv.addWeighted(scale_x,0.5,scale_y,0.5,0)fig,axes = plt.subplots(1,2,figsize=(9,10))
axes[0].imshow(img_horse,cmap='gray')
axes[0].set_title("原图")
axes[1].imshow(res,cmap=plt.cm.gray)
axes[1].set_title("Scharr滤波后结果")
plt.show()
3.5.2 Laplacian算子
img_horse = cv.imread("horse.jpg",0)res = cv.Laplacian(img_horse,cv.CV_16S,ksize=3)
scale_res = cv.convertScaleAbs(res)fig,axes = plt.subplots(1,2,figsize=(9,10))
axes[0].imshow(img_horse,cmap='gray')
axes[0].set_title("原图")
axes[1].imshow(scale_res,cmap=plt.cm.gray)
axes[1].set_title("Laplacian滤波后结果")
plt.show()
3.5.3 Canny边缘检测
img_horse = cv.imread("horse.jpg",0)# Canny边缘检测,min_threshold最小阈值
min_threshold = 20
max_threshold = 100
res = cv.Canny(img_horse,min_threshold,max_threshold)fig,axes = plt.subplots(1,2,figsize=(9,10))
axes[0].imshow(img_horse,cmap='gray')
axes[0].set_title("原图")
axes[1].imshow(res,cmap=plt.cm.gray)
axes[1].set_title("Canny滤波后结果")
plt.show()
3.6 模板匹配和霍夫变换的应用
3.6.1 模板匹配
img_party = cv.imread("party.jpg")
template = cv.imread("template.jpg")h,w = template.shape[:2]# 模板匹配
res = cv.matchTemplate(img_party,template,cv.TM_SQDIFF)
# 返回图像最佳匹配位置,确定左上角的坐标
min_val,max_val,min_loc,max_loc = cv.minMaxLoc(res)# 使用平方差时(cv.TM_SQDIFF)最小值为最佳匹配位置
top_left = min_loc
bottom_right = (top_left[0]+h,top_left[1]+w)cv.rectangle(img_party,top_left,bottom_right,(0,255,0),2)
fig,axes = plt.subplots(1,2,figsize=(10,8),gridspec_kw={'width_ratios': [1, 6]})
axes[0].imshow(template[:,:,::-1])
axes[0].set_title("匹配模板")
axes[1].imshow(img_party[:,:,::-1])
axes[1].set_title("匹配结果")
plt.tight_layout()
plt.show()
3.6.2 霍夫变换
# 读取图像
img_rili = cv.imread("rili.jpg")# 使用Canny转换为二值图
gray = cv.cvtColor(img_rili,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,100,200)# 霍夫直线变换
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 * rhoy0 = b * rhox1 = int(x0 - 1000 * b)y1 = int(y0 + 1000 * a)x2 = int(x0 + 1000 * b)y2 = int(y0 - 1000 * a)cv.line(img_rili, (x1, y1), (x2, y2), (0, 0, 255), 2)# 使用matplotlib显示图像
plt.imshow(img_rili[:, :, ::-1])
plt.xticks([]), plt.yticks([])
plt.title("霍夫变换直线检测")
plt.show()
3.7 图像变化
3.7.1 傅里叶变换
读取图像: 读取图像并转换为灰度图像。 傅里叶变换: 正变换:将图像转换为频域表示。 频谱中心化:将频谱的低频部分移到中心,高频部分移到四周。 计算频谱和相位谱:将复数形式的频谱转换为幅度和相位,并对幅度谱进行对数变换。 傅里叶逆变换: 反变换:将频域表示转换回时域(或空域)。 计算灰度值:计算逆变换后的图像的幅度。 显示结果: 使用 matplotlib 显示原始图像、频谱图和逆变换后的图像。
img_dog= cv.imread("dog.jpg",0)# 傅里叶正变换,cv.DFT_COMPLEX_OUTPUT:指定输出为复数形式
dft = cv.dft(np.float32(img_dog),flags=cv.DFT_COMPLEX_OUTPUT)
# 频谱中心化
dft_shift = np.fft.fftshift(dft)# 计算频谱和相位谱
mag,angle = cv.cartToPolar(dft_shift[:,:,0],dft_shift[:,:,-1],angleInDegrees=True)
# 对幅度谱进行对数变换,以便更好地可视化。对数变换可以压缩动态范围,使图像的细节更明显。
mag = 20 * np.log(mag)# 傅里叶反变换
img_back = cv.idft(dft)
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])fig,axes = plt.subplots(2,2,figsize=(10,8))
axes[0,0].imshow(img_dog,cmap='gray')
axes[0,0].set_title("原图")
axes[0,1].imshow(mag,cmap='gray')
axes[0,1].set_title("频谱")
axes[1,0].imshow(angle,cmap='gray')
axes[1,0].set_title("相位谱")
axes[1,1].imshow(img_back,cmap='gray')
axes[1,1].set_title("逆变换结果")
plt.show()
3.7.2 高通和低通滤波
# 高通滤波
dog_img = cv.imread("dog.jpg",0)rows,cols = dog_img.shape
mask = np.ones((rows,cols,2),np.uint8)
mask[int(rows/2)-30:int(rows/2)+30,int(cols/2)-30:int(cols/2)+30,:] = 0# 正变换
dft = cv.dft(np.float32(dog_img),flags=cv.DFT_COMPLEX_OUTPUT)
# 频谱中心化
dft_shift = np.fft.fftshift(dft)
# 滤波(移除低频)
dft_shift = dft_shift * mask
# 频谱中心化
dft_shift = np.fft.fftshift(dft_shift)# 反变化
img_back = cv.idft(dft_shift)
# 计算灰度值
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(dog_img, cmap = 'gray')
axes[0].set_title('原图')
axes[1].imshow(img_back, cmap = 'gray')
axes[1].set_title('高通滤波结果')
plt.show()
# 低通滤波
dog_img = cv.imread("dog.jpg",0)rows,cols = dog_img.shape
mask = np.zeros((rows,cols,2),np.uint8)
mask[int(rows/2)-30:int(rows/2)+30,int(cols/2)-30:int(cols/2)+30,:] = 1# 正变换
dft = cv.dft(np.float32(dog_img),flags=cv.DFT_COMPLEX_OUTPUT)
# 频谱中心化
dft_shift = np.fft.fftshift(dft)
# 滤波(移除低频)
dft_shift = dft_shift * mask
# 频谱中心化
dft_shift = np.fft.fftshift(dft_shift)# 反变化
img_back = cv.idft(dft_shift)
# 计算灰度值
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(dog_img, cmap = 'gray')
axes[0].set_title('原图')
axes[1].imshow(img_back, cmap = 'gray')
axes[1].set_title('低通滤波结果')
plt.show()
3.7.3 带通和带阻滤波
# 带通滤波
dog_img = cv.imread("dog.jpg",0)rows,cols = dog_img.shape
mask1 = np.ones((rows,cols,2),np.uint8)
mask1[int(rows/2)-8:int(rows/2)+8,int(cols/2)-8:int(cols/2)+8] = 0
mask2 = np.zeros((rows,cols,2),np.uint8)
mask2[int(rows/2)-80:int(rows/2)+80,int(cols/2)-80:int(cols/2)+80] = 1
mask = mask1*mask2# 正变换
dft = cv.dft(np.float32(dog_img),flags=cv.DFT_COMPLEX_OUTPUT)
# 频谱中心化
dft_shift = np.fft.fftshift(dft)
# 滤波(移除低频)
dft_shift = dft_shift * mask
# 频谱中心化
dft_shift = np.fft.fftshift(dft_shift)# 反变化
img_back = cv.idft(dft_shift)
# 计算灰度值
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(dog_img, cmap = 'gray')
axes[0].set_title('原图')
axes[1].imshow(img_back, cmap = 'gray')
axes[1].set_title('带通滤波结果')
plt.show()
# 带阻滤波
dog_img = cv.imread("dog.jpg",0)rows,cols = dog_img.shape
mask = np.ones((rows,cols,2),np.uint8)
mask[int(rows/2)+60:int(rows/2)+130,int(cols/2)-130:int(cols/2)+130] = 0
mask[int(rows/2)-130:int(rows/2)-60,int(cols/2)-130:int(cols/2)+130] = 0
mask[int(rows/2)-130:int(rows/2)+130,int(cols/2)+60:int(cols/2)+130] = 0
mask[int(rows/2)-130:int(rows/2)+130,int(cols/2)-130:int(cols/2)-60] = 0# 正变换
dft = cv.dft(np.float32(dog_img),flags=cv.DFT_COMPLEX_OUTPUT)
# 频谱中心化
dft_shift = np.fft.fftshift(dft)
# 滤波(移除低频)
dft_shift = dft_shift * mask
# 频谱中心化
dft_shift = np.fft.fftshift(dft_shift)# 反变化
img_back = cv.idft(dft_shift)
# 计算灰度值
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(dog_img, cmap = 'gray')
axes[0].set_title('原图')
axes[1].imshow(img_back, cmap = 'gray')
axes[1].set_title('带阻滤波结果')
plt.show()
3.8 轮廓检测与轮廓特征
3.8.1 轮廓检测
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
ditu = cv.imread("ditu.jpg")
# 复制原图
img_ditu = ditu.copy()
imggray = cv.cvtColor(ditu,cv.COLOR_BGR2GRAY)
canny = cv.Canny(imggray,120,255)# 轮廓提取
contours,hierarchy = cv.findContours(canny,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)
# 将轮廓绘制在图形上
img = cv.drawContours(ditu,contours,-1,(0,0,255),2)fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(img_ditu[:,:,::-1])
axes[0].set_title("原图")
axes[1].imshow(img[:,:,::-1])
axes[1].set_title("轮廓")
plt.show()
3.8.2 轮廓特征
- 轮廓面积
area = sum(cv.contourArea(cnt) for cnt in contours)
area
- 轮廓周长
perimeter = sum(cv.arcLength(cnt,True) for cnt in contours)
perimeter
- 轮廓近似
# 读取图像
img = cv.imread("jinsi.jpg")# 灰度转换
imggray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)# 二值化处理
ret, thresh = cv.threshold(imggray, 127, 255, cv.THRESH_BINARY)# 轮廓提取
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)# 初始化绘制图像
img_contours = img.copy()
img_approx = img.copy()# 处理所有轮廓
for cnt in contours:# 计算轮廓的弧长arc_length = cv.arcLength(cnt, True)# 计算近似多边形epsilon = 0.1 * arc_lengthapprox = cv.approxPolyDP(cnt, epsilon, True)# 绘制原始轮廓和近似多边形(-1表示绘制所有轮廓)img_contours = cv.drawContours(img_contours, [cnt], -1, (0, 255, 0), 2)img_approx = cv.drawContours(img_approx, [approx], -1, (0, 255, 0), 2)# 显示图像
fig, axes = plt.subplots(1, 3, figsize=(10, 13))
axes[0].imshow(ditu[:, :, ::-1])
axes[0].set_title("原图")
axes[1].imshow(img_contours[:, :, ::-1])
axes[1].set_title("原始轮廓")
axes[2].imshow(img_approx[:, :, ::-1])
axes[2].set_title("近似多边形")
plt.show()
- 凸包
star = cv.imread("star.jpg")# 灰度处理
imggray = cv.cvtColor(star,cv.COLOR_BGR2GRAY)
# 边缘检测
canny = cv.Canny(imggray,50,200)# 获取轮廓
contours,hierarchy = cv.findContours(canny,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)# 图像复制
img_star = star.copy()#凸包检测
Hulls = []
for cnt in contours:hull = cv.convexHull(cnt)Hulls.append(hull)# 绘制图形
img_contour = cv.drawContours(star,contours,-1,(255,0,0),2)
img_hull = cv.drawContours(img_star,Hulls,-1,(255,0,0),2)fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(img_contour[:,:,::-1])
axes[0].set_title("轮廓检测结果")
axes[1].imshow(img_hull[:,:,::-1])
axes[1].set_title("凸包结果")
plt.show()
- 边界矩形
rect = cv.imread("rect.jpg")# 灰度处理
imggray = cv.cvtColor(rect,cv.COLOR_BGR2GRAY)
# 转换为二值化
ret,thresh = cv.threshold(imggray,127,255,0)# 轮廓提取
contours,hierarchy = cv.findContours(thresh,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)# 图像复制
rect_img = rect.copy()# 直边界矩形
bounding_box = []
for cnt in contours:x,y,w,h = cv.boundingRect(cnt)bounding_box.append((x,y,w,h))
for x,y,w,h in bounding_box:cv.rectangle(rect,(x,y),(x+w,y+h),(0,255,0),2)# 旋转边界矩形
min_area_rects = []
for cnt in contours:rect_min = cv.minAreaRect(cnt)box = cv.boxPoints(rect_min)box = np.int0(box)min_area_rects.append(box)
for box in min_area_rects:cv.polylines(rect_img,[box],True,(0,255,0),2)fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(rect[:,:,::-1])
axes[0].set_title("直边界矩形")
axes[0].set_xticks([]),axes[0].set_yticks([])
axes[1].imshow(rect_img[:,:,::-1])
axes[1].set_title("旋转边界矩形")
axes[1].set_xticks([]),axes[1].set_yticks([])
plt.show()
- 最小外接圆
img = cv.imread("rect.jpg")imggray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret,thresh = cv.threshold(imggray,127,255,0)contours,hierarchy = cv.findContours(thresh,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)boundings = []
for cnt in contours:(x,y),radius = cv.minEnclosingCircle(cnt)center = (int(x),int(y))radius = int(radius)boundings.append((center,radius))
for center,radius in boundings:cv.circle(img,center,radius,(0,255,0),2)plt.imshow(img[:,:,::-1])
plt.xticks([])
plt.yticks([])
plt.show()
- 椭圆拟合
img = cv.imread("rect.jpg")imggray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret,thresh = cv.threshold(imggray,127,255,0)contours,hierarchy = cv.findContours(thresh,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)boundings = []
for cnt in contours:# 过滤掉点数少于5个和面积过小的轮廓if len(cnt) >= 5 and cv.contourArea(cnt) > 100:ellipse = cv.fitEllipse(cnt)boundings.append(ellipse)
for ellipse in boundings:cv.ellipse(img,ellipse,(0,255,0),2)plt.imshow(img[:,:,::-1])
plt.xticks([])
plt.yticks([])
plt.show()
3.9 图像分割
3.9.1 全阈值分割
img = cv.imread("gradient.jpg",0)ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)
ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)
ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)
ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)titles = ["原图","阈值二值化","阈值反二值化","截断","阈值取零","阈值反取零"]
images = [img,thresh1,thresh2,thresh3,thresh4,thresh5]
plt.figure(figsize=(10,8))
for i in range(6):plt.subplot(2,3,i+1)plt.imshow(images[i],cmap='gray')plt.title(titles[i])plt.show()
3.9.2 自适应阈值分割
fruit = cv.imread("fruit.jpg",0)# 固定阈值
ret,threshold = cv.threshold(fruit,127,225,cv.THRESH_BINARY)
# 自适应阈值
# 领域内求平均值
th1 = cv.adaptiveThreshold(fruit,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,11,4)
# 领域内高斯加权
th2 = cv.adaptiveThreshold(fruit,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,17,6)title = ["原图","固定阈值","自适应阈值(求均值)","自适应阈值(高斯加权)"]
images = [fruit,threshold,th1,th2]plt.figure(figsize=(10,8))
for i in range(4):plt.subplot(2,2,i+1)plt.imshow(images[i],cmap="gray")plt.title(title[i])
plt.show()
3.9.3 Ostu阈值(大律法)
littledog = cv.imread("littledog.jpg",0)# 固定阈值
ret,thresh = cv.threshold(littledog,40,255,cv.THRESH_BINARY)
# ostu分割
ret1,thresh2 = cv.threshold(littledog,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)fig,axes = plt.subplots(1,3,figsize=(10,8))
axes[0].imshow(littledog,cmap="gray")
axes[0].set_title("原图")
axes[1].imshow(thresh,cmap="gray")
axes[1].set_title("全阈值分割")
axes[2].imshow(thresh2,cmap="gray")
axes[2].set_title("OStu分割")
plt.show()
3.9.4 分水岭算法
img = cv.imread("horse.jpg")imggray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 边缘检测
canny = cv.Canny(imggray,127,255)
# 轮廓检测
contours,hierarchy = cv.findContours(canny,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)
# 初始化标记图像
marks = np.zeros(img.shape[:2],np.int32)# 绘制轮廓
for index in range(len(contours)):# index:-1 绘制所有的轮廓,非负数:要绘制的轮廓的索引marks = cv.drawContours(marks,contours,index,(index,index,index),1,8,hierarchy)# 使用分水岭算法
# img必须是8位无符号整数的三通道图像,marks必须是32位有符号整数的单通道图像
# 返回值:正整数:表示该像素属于某个特定区域,-1表示该像素是区域的边界
marks = cv.watershed(img,marks)# 生成随机颜色
colours = np.zeros((np.max(marks) + 1,3))
for i in range(len(colours)):aa = np.random.uniform(0,255)bb = np.random.uniform(0,255)cc = np.random.uniform(0,255)colours[i] = np.array([aa,bb,cc],np.uint8)# 对每个区域进行颜色填充
bgrimg = np.zeros(img.shape,np.uint8)
index = 0
for i in range(marks.shape[0]):for j in range(marks.shape[1]):index = marks[i][j]if index == -1:bgrimg[i][j] = np.array([255,255,255])else:bgrimg[i][j] = colours[index]plt.imshow(bgrimg[:,:,::-1])
plt.title("图像分割结果")
plt.show()
3.9.5 GrabCut算法
img = cv.imread("liying.jpg")masks = np.zeros(img.shape[:2],np.uint8)
# 矩形窗口,指定前景区域
rect = [260,50,740,730]# 前景和背景分割
cv.grabCut(img,masks,tuple(rect),None,None,30,cv.GC_INIT_WITH_RECT)# 抠取图像
mask2 = np.where((masks==2)|(masks==0),0,1).astype("uint8")
img_show = img * mask2[:,:,np.newaxis]
# 将矩形绘制在图像上
cv.rectangle(img,(260,50),(1000,780),(255,0,0),2)fig,axes = plt.subplots(1,2,figsize=(10,8))
axes[0].imshow(img[:,:,::-1])
axes[0].set_title("矩形框选位置")
axes[1].imshow(img_show[:,:,::-1])
axes[1].set_title("扣取结果")
plt.show()
四、图像的特征提取与描述
- 图像特征要有区分性,容易被比较。一般认为角点、斑点等是比较好的图像特征
- 特征检测:找到图像中的特征
- 特征描述:对特征及其周围的区域描述
4.1 Harris角点检测
Harris角点检测的思想是通过图像的局部的小窗口观察图像,角点的特征是窗口沿任意方向移动都会导致图像灰度明显变化。
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 对棋盘进行角点检测
qipan = cv.imread("qipan.jpg")gray = cv.cvtColor(qipan,cv.COLOR_BGR2GRAY)
gray = np.float32(gray)
# Harris角点检测
# 2,blockSize计算每个像素的角点响应时考虑的窗口大小
# 3,Sobel 算子用于计算图像的梯度,进而用于计算角点响应。
# 0.04,用于平衡角点检测的灵敏度
dst = cv.cornerHarris(gray,2,3,0.04)
# 设置阈值,选择 dst 中角点响应值大于阈值的像素位置
qipan[dst > 0.001*dst.max()] = [0,255,0]plt.figure(figsize=(10,8))
plt.imshow(qipan[:,:,::-1])
plt.show()
4.2 Shi-Tomasi角点检测
tv = cv.imread("tv.jpg")
gray = cv.cvtColor(tv,cv.COLOR_BGR2GRAY)# 提取角坐标
conners = cv.goodFeaturesToTrack(gray,1000,0.01,10)
# 绘制角点
for i in conners:# 将坐标展平为一维x,y = i.ravel()x,y = int(x),int(y)cv.circle(tv,(x,y),3,(0,255,0),-1)plt.figure(figsize=(10,8))
plt.imshow(tv[:,:,::-1])
plt.show()
4.3 sift算法
通过多尺度空间检测极值点作为关键点,确保尺度不变性;再对关键点邻域进行方向赋值,确保旋转不变性,从而实现对图像特征的稳定提取。
tv = cv.imread("tv.jpg")gray = cv.cvtColor(tv,cv.COLOR_BGR2GRAY)# 实例化shif
sift = cv.xfeatures2d.SIFT_create()
# 角点检测:kp角点的信息包括坐标,方向等 des角点描述
kp, des = sift.detectAndCompute(gray,None)
# 绘制角点
cv.drawKeypoints(tv,kp,tv,flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)plt.figure(figsize=(10,8))
plt.imshow(tv[:,:,::-1])
plt.show()
4.4 fast检测算法
若一个像素周围有一定数量的像素与该点像素值不同,则认为其为角点
tv = cv.imread("tv.jpg")# 实例化fast对象
fast = cv.FastFeatureDetector_create(threshold=30)
# 检测关键的
kp = fast.detect(tv,None)
# 绘制关键点,默认开启非极大值抑制,抑制候选角点的重叠
img1 = cv.drawKeypoints(tv,kp,None,(0,0,255))# 关闭非极大值抑制
fast.setNonmaxSuppression(0)
kp = fast.detect(tv,None)
img2 = cv.drawKeypoints(tv,kp,None,(0,0,255))plt.figure(figsize=(10,8))
plt.subplot(121)
plt.imshow(img1[:,:,::-1])
plt.title("开启非极大值抑制")
plt.subplot(122)
plt.imshow(img2[:,:,::-1])
plt.title("关闭非极大值抑制")
plt.show()
4.5 orb角点检测
tv = cv.imread("tv.jpg")# 实例化ORB
# nfeatures设置要检测的最大特征点数量
orb = cv.ORB_create(nfeatures=200)
# 角点检测
kp,des = orb.detectAndCompute(tv,None)
# 绘制角点
cv.drawKeypoints(tv,kp,tv,(0,255,0))plt.figure(figsize=(5,4))
plt.imshow(tv[:,:,::-1])
plt.show()
五、视频操作
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
5.1 视频读写
video_ying = cv.VideoCapture("赵丽颖.mp4")
# 查看是否捕获成功
video_ying.isOpened()
# 判断是否读取成功
while(video_ying.isOpened()):# 获取每一帧图像ret,frame = video_ying.read()if ret == True:cv.imshow("frame",frame)# 每一帧间隔50秒,按q退出if cv.waitKey(50) & 0xFF == ord('q'):break
# 释放VideoCapture对象,关闭视频文件
video_ying.release()
# 关闭OpenCV所创建的窗口
cv.destroyAllWindows()
5.2 视频保存
# 读取视频
cap = cv.VideoCapture("赵丽颖.mp4")# 获取图像的属性(宽度和高度),并将其转换为整数
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))# 创建保存视频的对象,设置编码格式,帧率,图像的宽度和高度
out = cv.VideoWriter('outpy.avi', cv.VideoWriter_fourcc('M', 'J', 'P', 'G'), 10, (frame_width, frame_height))# 循环读取视频中的每一帧图像
while True:# 获取视频中的每一帧图像ret, frame = cap.read() # 如果读取成功,将每一帧图像写入到输出文件中if ret == True:out.write(frame)else:break# 释放资源
cap.release()
out.release()
cv.destroyAllWindows()
5.3 视频追踪
目标:追踪视频中的小柯基
5.3.1 meanshift算法
简单,迭代次数少。但不能适应运动目标的形状和大小的变化
import cv2 as cv
import numpy as np
# 视频捕获
video_dog = cv.VideoCapture('dog.mp4')# 获取第一帧图像,并指定目标位置
ret, frame = video_dog.read()# 目标位置(行,高,列,宽)
r, h, c, w = 140, 230, 300, 150
track_window = (c, r, w, h)# 指定目标的感兴趣区域
roi = frame[r:r+h, c:c+w]# 计算直方图
# 转换色彩空间(HSV)
hsv_roi = cv.cvtColor(roi, cv.COLOR_BGR2HSV)# 去除低亮度的值(色调,饱和度,亮度)
mask = cv.inRange(hsv_roi, np.array((0, 100, 52)), np.array((180, 255, 255)))# 计算直方图
# [0] 只计算第一个通道,即色调(hue)通道的直方图
# [180] 定义直方图bin数量
# [0,180] 计算从0到180之间的色调值的直方图
roi_hist = cv.calcHist([hsv_roi],[0],mask,[180],[0,180])# 归一化
cv.normalize(roi_hist, roi_hist, 0, 255, cv.NORM_MINMAX)# 目标追踪
# 设置窗口搜索终止条件:最大迭代次数,窗口中心漂移最小值
term_crit = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1)while True:# 获取每一帧图像ret, frame = video_dog.read()if ret:# 算直方图的反向投影,生成一个概率图 dst,指示当前帧中哪些区域最可能包含目标。hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)dst = cv.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)# 进行Meanshift追踪ret, track_window = cv.meanShift(dst, track_window, term_crit)# 追踪的位置绘制在视频上,并进行显示x, y, w, h = track_windowimg2 = cv.rectangle(frame, (x, y), (x + w, y + h), 255, 2)cv.imshow('frame', img2)if cv.waitKey(65) & 0xFF == ord('q'):breakelse:breakvideo_dog.release()
cv.destroyAllWindows()
5.3.2 camshift算法
camshift算法可以适应目标大小形状的改变,具有较好的追踪效果。但当背景色和目标颜色接近时,容易使目标的区域变大。
import cv2 as cv
import numpy as npvideo_dog = cv.VideoCapture('dog.mp4')# 获取第一帧图像,并指定目标位置
ret, frame = video_dog.read()# 目标位置
r, h, c, w = 170, 150, 350, 90
track_window = (c, r, w, h)# 指定目标区域
roi = frame[r:r+h, c:c+w]# 计算直方图
# 转换色彩空间(HSV)
hsv_roi = cv.cvtColor(roi, cv.COLOR_BGR2HSV)# 去除低亮度的值(色调,饱和度,亮度)
mask = cv.inRange(hsv_roi, np.array((0, 100, 50)), np.array((180, 255, 255)))# 计算直方图
# [0] 只计算第一个通道,即色调(hue)通道的直方图
# [180] 定义直方图bin数量
# [0,180] 计算从0到180之间的色调值的直方图
roi_hist = cv.calcHist([hsv_roi],[0],mask,[180],[0,180])# 归一化
cv.normalize(roi_hist, roi_hist, 0, 255, cv.NORM_MINMAX)# 目标追踪
# 设置窗口搜索终止条件:最大迭代次数,窗口中心漂移最小值
term_crit = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1)while True:ret, frame = video_dog.read()if ret:# 计算直方图的反向投影,生成一个概率图 dst,指示当前帧中哪些区域最可能包含目标。hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)dst = cv.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)# CamShift追踪ret, track_window = cv.CamShift(dst, track_window, term_crit)# 将追踪的位置绘制在视频上,并进行显示# pst矩形框的四个坐标pts = cv.boxPoints(ret)pts = np.intp(pts)img2 = cv.polylines(frame,[pts],True, 255,2)# 显示图像cv.imshow('frame', img2)if cv.waitKey(60) & 0xFF == ord('q'):breakelse:breakvideo_dog.release()
cv.destroyAllWindows()
六、人脸、眼睛检测案例
OpenCV中自带已训练好的检测器,包括面部、眼睛等,都保存在XML中,我们可以通过以下程序找到他们:
import cv2 as cv
print(cv.__file__)
所有的XML文件都在D:\Anaconda\Lib\site-packages\cv2\data\
中
6.1 人脸以及眼睛检测(图片)
img = cv.imread("liying2.jpg")
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)# 定义训练器路径
cascade_path = "D:\\Anaconda\\Lib\\site-packages\\cv2\\data\\haarcascade_frontalface_default.xml"
eye_cascade_path = "D:\\Anaconda\\Lib\\site-packages\\cv2\\data\\haarcascade_eye.xml"# 实例化人脸级联分类器
face_cas = cv.CascadeClassifier(cascade_path)
# 实例化眼睛级联分类器
eyes_cas = cv.CascadeClassifier(eye_cascade_path)# 人脸检测
faceRects = face_cas.detectMultiScale(gray,scaleFactor=1.05,minNeighbors=5,minSize=(20,20))
# 遍历人脸
for faceRect in faceRects:x,y,w,h = faceRectcv.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)roi_color = img[x:x+w,y:y+h]roi_gray = gray[x:x+w,y:y+h]eyes = eyes_cas.detectMultiScale(roi_gray,scaleFactor=1.2, minNeighbors=5, minSize=(30, 30), maxSize=(100, 100))for x,y,w,h in eyes:cv.rectangle(roi_color,(x,y),(x+w,y+h),(255,0,0),2)plt.figure(figsize=(7,4))
plt.imshow(img[:,:,::-1])
plt.title("检测结果")
plt.show()
6.2 人脸以及眼睛检测(视频)
import cv2 as cv
import matplotlib.pyplot as pltvideo = cv.VideoCapture("赵丽颖.mp4")cascade_path = "D:\\Anaconda\\Lib\\site-packages\\cv2\\data\\haarcascade_frontalface_default.xml"
eyes_cascade_path = "D:\\Anaconda\\Lib\\site-packages\\cv2\\data\\haarcascade_eye.xml"while True:ret,frame = video.read()if ret==True:gray = cv.cvtColor(frame,cv.COLOR_BGR2GRAY)# 实例化人脸级联分类器face_cas = cv.CascadeClassifier(cascade_path)# 实例化眼睛级联分类器eyes_cas = cv.CascadeClassifier(eyes_cascade_path)# 检测人脸faceRects = face_cas.detectMultiScale(gray,scaleFactor=1.2,minNeighbors=3,minSize=(60,60))for faceRect in faceRects:x,y,w,h = faceRectcv.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)roi_color = frame[y:y+h,x:x+w]# 定位人脸上半部分roi_gray = gray[y:y+int(h*0.7),x:x+w]eyes = eyes_cas.detectMultiScale(roi_gray,scaleFactor=1.3,minNeighbors=5, minSize=(20,20), maxSize=(100, 100))for x,y,w,h in eyes:cv.rectangle(roi_color,(x,y),(x+w,y+h),(255,0,0),2)cv.imshow("frame",frame)if cv.waitKey(20) & 0xFF==ord('q'):breakelse:break
video.release()
cv.destroyAllWindows()
由于运行结果是视频所以无法展示
相关文章:
OpenCV计算机视觉库
计算机视觉和图像处理 Tensorflow入门深度神经网络图像分类目标检测图像分割OpenCVPytorchNLP自然语言处理 OpenCV 一、OpenCV简介1.1 简介1.2 OpenCV部署1.3 OpenCV模块 二、OpenCV基本操作2.1 图像的基本操作2.1.1 图像的IO操作2.1.2 绘制几何图像2.1.3 获取并修改图像的像素…...
CentOS 系统中的文件挂载 U 盘
要将 CentOS 系统中的文件保存到 U 盘,可以按照以下步骤进行操作: 一、插入 U 盘并确定设备名称 将 U 盘插入 CentOS 系统的 USB 接口。使用 fdisk -l 命令查看系统中的磁盘和分区情况,确定 U 盘的设备名称。通常 U 盘会显示为类似于 /dev/…...
Lumerical脚本语言-变量操作(Manipulating variables)
下面的命令用来创建和存取变量。 命令描述= 赋值操作符 :数组操作符 []创建矩阵 % 创建包含空格的变量名称 linspace 创建线性空间数组 matrix 创建一个全为 0 的矩阵 randmatrix 创建一个所有元素为 0~1 之间的一个随机数的矩阵 randnmatrix 创建一个所有元素为平均值为 0…...
一个基本的包括爬虫、数据存储和前端展示框架0
创建一个完整的网络爬虫和前端展示页面是一个涉及多个步骤和技术的任务。下面我将为你提供一个基本的框架,包括爬虫代码(使用Python和Scrapy框架)和前端HTML页面(伏羲.html)。 爬虫代码 (使用Scrapy) 首先,你需要安装Scrapy库:bash pip install scrapy 然后,创建一个新…...
简历制作面试篇
一.面试技巧分析 模板: 推荐使用简洁一点的模板,不要太花哨,能够让HR和面试官清楚,快速知道信息就可以,太花哨容易分散别人的注意力。 格式: 一般选用PDF,不要用WORD。 照片: 技术岗一般不用贴照片,推进写上自己的联系方式或者微信。 专业技能: 描述专业技能…...
智能制造--EAP设备自动化程序
EAP是设备自动化程序(Equipment Automation Program)的缩写,他是一种用于控制制造设备进行自动化生产的系统。EAP系统与MES系统整合,校验产品信息,自动做账,同时收集产品生产过程中的制程数据和设备参数数据…...
LabVIEW混合控制器质量检测
随着工业自动化水平的提高,对控制器的精度、稳定性、可靠性要求也在不断上升。特别是在工程机械、自动化生产、风力发电等领域,传统的质量检测方法已无法满足现代工业的高要求。因此,开发一套自动化、精确、可扩展的混合控制器质量检测平台成…...
新技术浪潮下的等保测评:云计算、物联网与大数据的挑战与机遇
随着信息技术的飞速发展,云计算、物联网(IoT)和大数据等新兴技术正以前所未有的速度改变着我们的生活和工作方式。这些技术的广泛应用不仅为信息系统带来了前所未有的性能提升,同时也对等保测评(信息安全等级保护测评&…...
微信小程序技术框架选型
“近期在对团队的微信小程序进行技术框架选型,故对目前主流的微信小程序技术框架进行了一些分析和比较,包括各框架的维护团队、社区链接、GitHub star数、优缺点对比等方面,为团队提供技术框架选型参考” 一、引言 随着移动互联网的快速发展…...
SQL学习3
24.10.3学习目录 一.c语言操作数据库 一.c语言操作数据库 (1)打开、关闭数据库函数 //打开数据库 int sqlite3_open(char *db_name,sqlite3 **db);db_name:数据库文件名,若文件名中有ASCLL码中以外的字符,其必须为UT…...
Linux:进程控制(一)
目录 一、写时拷贝 1.创建子进程 2.写时拷贝 二、进程终止 1.函数返回值 2.错误码 3.异常退出 4.exit 5._exit 一、写时拷贝 父子进程,代码共享,不作写入操作时,数据也是共享的,当任意一方试图写入,便通过写时拷…...
初识算法 · 双指针(3)
目录 前言: 和为s的两数之和 题目解析: 编辑 算法原理: 算法编写: 三数之和 题目解析 算法原理 算法编写 前言: 本文通过介绍和为S的两数之和,以及三数之和,对双指针算法进行深一步…...
【AI知识点】近似最近邻搜索(ANN, Approximate Nearest Neighbor Search)
近似最近邻搜索(ANN, Approximate Nearest Neighbor Search) 是一种用于高维数据检索的技术,目标是在给定查询的情况下,快速找到距离查询点最近的数据点,尽管结果可能并不完全精确。这种方法特别适用于高维数据&#x…...
编程工具简介
在编程工作中,选择合适的工具确实能够显著提升工作效率。以下是一些被广泛推荐的工具: 1. Visual Studio Code (VS Code):这是一款轻量级但功能强大的代码编辑器,支持多种编程语言,拥有丰富的插件生态系统࿰…...
汽车信息安全 -- 存到HSM中的密钥还需包裹吗?
目录 1.车规芯片的ROM_KEY 2.密钥加密与包裹 3.瑞萨RZ\T2M的密钥导入 4.小结 在车控类ECU中,我们通常把主控芯片MCU中的HSM以及HSM固件统一看做整个系统安全架构的信任根。 所以大家默认在HSM内部存储的数据等都是可信的,例如CycurHSM方案中使用HSM…...
【PostgreSQL】入门篇——SELECT、INSERT、UPDATE 和 DELETE 语句,SQL 中最常用的四种操作用法
1. SELECT 语句 描述 SELECT 语句用于从数据库中查询数据。可以选择特定的列或所有列,并可以通过条件过滤结果。 语法 SELECT column1, column2, ... FROM table_name WHERE condition;示例 假设我们有一个名为 employees 的表,结构如下:…...
【Ubuntu】安装常用软件包-mysql
我的几个服务是部署在docker的同一个网络里,这样相互访问就可以通过docker容器的名字访问,比如容器A访问容器B,就可以http://B:8080/xxx 这样访问,不用关心ip是多少。 所以mysql前面文章给安装到主机里,感觉有点坑自己…...
幂等性及技术解决方案
文章目录 定义幂等性 为什么需要幂等性幂等性设计注意事项幂等性的范围分布式锁解决幂等性 设计 延伸阅读 定义幂等性 简单地说,我们可以多次执行幂等运算而不改变结果或者使用相同的输入参数中被调用多次,则不具有额外效果的操作,也就是多…...
正向代理 反向代理
正向代理 正向代理是一种网络服务,它作为客户端和目标服务器之间的中间人,代表客户端向目标服务器发送请求并接收响应。以下是关于正向代理的详细解释: 工作原理 客户端配置: 客户端(如浏览器)配置为使用…...
【分布式微服务云原生】如何在ActiveMQ中优雅处理提前支付的延时订单
摘要 本文将深入探讨在ActiveMQ中如何处理用户提前支付的延时订单问题。我们将介绍如何通过更新订单状态、检查延迟任务、取消延迟消息、使用死信队列、消息选择性消费、设置合理的超时时间以及及时反馈和日志记录等策略,来确保系统的一致性和及时响应用户操作。文…...
Easy Excel从入门到精通!!!
目录 1.文件导入 1.1基本方式读取excel文件内容 1.2注解模型映射器读取excel 1.3多行表头读取 1.4文件上传读取 2.文件导出 2.1基本方式导出 2.2模型映射导出 2.3设置行高、列宽等内容 2.4合并单元格 2.5导出设置超链接、批注、公式 2.6模板填充对象导出 2.7模板填…...
简易CPU设计入门:取指令(三),ip_buf与rd_en的非阻塞赋值
在开篇,还是请大家首先准备好本项目所用的源代码。如果已经下载了,那就不用重复下载了。如果还没有下载,那么,请大家点击下方链接,来了解下载本项目的CPU源代码的方法。 下载本项目代码 准备好了项目源代码以后&…...
【算法】---归并排序(递归非递归实现)
参考 左程云算法 算法导论 前言 本篇介绍 归并排序分治法 前置知识 了解递归, 了解数组。 引入 归并排序 归并排序最早是由公认的现代计算机之父John von Neumann发明的, 这是一种典型的分治思想应用。 我们先介绍分治思想 分治思想 分治思想的…...
UniVue大版本更新:UniVue2.0.0-preview
大版本发布说明 距离上次更新好像已经过去很久了,最近太忙了没时间维护新版本,也是自己在使用的过程中发现了很多问题也有了更多的灵感,由于和之前的版本区别太大,决定重新开一个大版本。这个UniVue2之后的版本追求是性能…...
RabbbitMQ篇(环境搭建 - 下载 安装)(持续更新迭代)
目录 一、Windows 1. 下载安装程序 2. 安装配置erlang 3. 安装rabbitMQ 4. 验证 二、Linux 1. 下载rpm包 1.1. 下载Erlang的rpm包 1.2. 下载socat的rpm包 1.3. 下载RabbitMQ的rpm包 2. 安装 2.1. 安装Erlang 2.2. 安装socat 2.3. 安装RabbitMQ 3. 启动RabbitMQ服…...
C++基础补充(02)C++其他控制语句break continue goto等
文章目录 1. break2. continue 语句3. goto 语句goto的存在 4. 跳出多重循环4.1 goto 直接跳转4.2 C11及其后版本的 return 语句4.3 使用标志变量 在C中,控制语句用于管理程序的执行流程。常见有 break、continue 和 goto。 1. break break语句主要用于在循环或者s…...
决策树中联合概率分布公式解释说明
学习决策树时书本中有一公式 7-3 是: P ( X x i , Y y j ) p i j ( i 1 , 2 , … , m , j 1 , 2 , … , n ) P(X x_i, Y y_j) p_{ij} \quad (i 1, 2, \dots, m, \ j 1, 2, \dots, n) P(Xxi,Yyj)pij(i1,2,…,m, j1,2,…,n) 这个公式表示的是随机变…...
计算机毕业设计 农场投入品运营管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…...
php email功能实现:详细步骤与配置技巧?
php email发送功能详细教程?如何使用php email服务? 无论是用户注册、密码重置,还是订单确认,电子邮件都是与用户沟通的重要手段。AokSend将详细介绍如何实现php email功能,并提供一些配置技巧,帮助你更好…...
MapBox Android版开发 6 关于Logo
MapBox Android版开发 6 关于Logo Logo的显示查看源码及思路(Logo)第一步第二步 隐藏Logo示例查看源码及思路(Info)第一步第二步 隐藏Logo和Info示例 看到有网友留言问如何移除Logo,今天看了下V9源码,发现M…...
影楼网站推广/软文范例200字
1、首先确定测试范围,测试设计,测试模块,再根据每个测试模块输出测试用例, 即:先确定要测试什么,测试哪些东西,要测试这些东西又要分别怎么测试,通过什么方法测试,这种方…...
专业做家电的网站/腾讯广告推广怎么做
点击关注公众号,实用技术文章及时了解功能说明nginxWebUI是一款图形化管理nginx配置的工具,可以使用网页来快速配置nginx的各项功能,包括http协议转发、tcp协议转发、反向代理、负载均衡、静态html服务器、ssl证书自动申请、续签、配置等。配…...
大连百事通国际旅行社/seo优化效果怎么样
gradle快速教程,无需在带有Gradle Nexus Staging插件的Nexus GUI中单击即可将Gradle项目中的工件提升/发布到Maven Central。 介绍 Maven Central (又名The Central Repository)(可能是)是Java和基于JVM的项目使用的世界上最大的开源工件集。 它是由Apache Maven的创…...
手机网站 cms/人工智能培训机构哪个好
mysql 创建用户自定义函数 为了防止分号产生的中途输出,自己定义一个 分隔符,这里仿照mysql官方的例子:使用两个美元符号 $$ 作为分割符号,下面这段代码就是创建一个自定义mysql函数的原型了,可以在这个基础上修改&…...
北京网站建设企业/网络营销方案策划论文
Class类 Class类是反射中的核心类 Java中每个类都有一个相对应的Class类的对象,JVM加载类时会创建一个该类的Class类对象,此Class类对象用于保存该类的类型信息Class类常用的方法 获取类中的属性: - getFields(): 获取类中所有的公共字段…...
公司网站开发费用计入/福州百度seo
网站设置-》导航-》全局导航添加链接-》设置标题和url-》保存 转载于:https://www.cnblogs.com/King-JJ/p/5553034.html...