P.S.代码内容取自以下这篇博客:
https://blog.csdn.net/qq_45874897/article/details/105516981
带注释代码:
""" 从视频读取帧保存为图片"""
import cv2
import numpy as np
#既可以通过视频内容检测也可以调用摄像头实时检测,根据自己的需要选择
#注意:如果选择视频需要根据自己视频存放的位置更改路径,不能照搬照套
#1、读取视频文件
#cap = cv2.VideoCapture("C:/Users/lenovo/Videos/1.mp4")
#2、读取摄像头
#参数0表示默认为笔记本的内置第一个摄像头
cap = cv2.VideoCapture(0)
#肤色检测
def A(img):
YCrCb = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB) #RGB转换至YCrCb空间,三维的空间将为二维的CrCb
#print(img)
#print(YCrCb)
(y,cr,cb) = cv2.split(YCrCb) #拆分出Y,Cr,Cb值(即图片通道拆分),Y是亮度,Cr是色调,Cb是饱和度
#print((y,cr,cb))
#实现高斯模糊
#(5, 5)表示高斯矩阵的长与宽都是5,标准差取0
cr1 = cv2.GaussianBlur(cr, (5,5), 0)
#cv2.imshow('GaussianBlur',cr1)
#cv2.waitKey(0)
#cv2.destroyAllWindows()
#print(cr1)
#过滤图像背景
#如果像素值小于阈值,则将其设置为0,否则将其设置为最大值
#cv.threshold第一个参数是源图像,它应该是灰度图像
#第二个参数是阈值,用于对像素值进行分类
#第三个参数是分配给超过阈值的像素值的最大值
#第四个参数是不同类型的阈值
#该方法返回两个输出:第一个是使用的阈值,第二个输出是阈值后的图像
_, skin = cv2.threshold(cr1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) #Ostu处理
#img的两个掩码取并集
#mask=skin表示要提取的区域
res = cv2.bitwise_and(img,img, mask = skin)
return res
#轮廓处理
def B(img):
#binaryimg = cv2.Canny(Laplacian, 50, 200) #二值化,canny检测
#寻找轮廓
#findcontour()第一个参数是源图像,第二个参数是轮廓检索模式,第三个参数是轮廓逼近方法。
#第二个参数RECT_EXTERNAL只检测最外层轮廓
#第三个参数存储形状边界的(x,y)坐标
h = cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
#print(h)
contour = h[0]
#print(contour)
contour = sorted(contour, key = cv2.contourArea, reverse=True)#对已轮廓区域面积进行排序用于找到最大轮廓
#contourmax = contour[0][:, 0, :]#保留区域面积最大的轮廓点坐标
bg = np.ones(dst.shape, np.uint8) *255#创建白色幕布
#print(np.ones(dst.shape, np.uint8))
#print (bg)
#bg是白色幕布,contours是轮廓,-1表示全画,然后是颜色,厚度
ret = cv2.drawContours(bg,contour[0],-1,(0,255,0),3) #绘制黑色轮廓
return ret
while(True):
#cap.read()按帧读取视频,返回值ret是布尔型,正确读取则返回True,读取失败或读取视频结尾则会返回False
#frame为每一帧的图像,这里图像是三维矩阵,例frame.shape = (640,480,3),读取的图像为BGR格式
ret, frame = cap.read()
#下面三行可以根据自己的电脑进行调节
src = cv2.resize(frame,(400,350), interpolation=cv2.INTER_CUBIC)#窗口大小
cv2.rectangle(src, (90, 60), (300, 300 ), (0, 255, 0))#框出截取位置
roi = src[60:300 , 90:300] #获取手势框图
res = A(roi) #进行肤色检测
#cv2.imShow()函数可以在窗口中显示图像
#第一个参数是字符串类型,用于表示窗口名称
#第二个参数是图像
cv2.imshow("CameraCapture",roi)
#我认为以下5行代码有前向传播的意味
gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY) #RGB图像转换成灰度图像
# 计算图像的边缘信息
# 第一个参数为输入的图像
# 第二个参数为输出图像的深度
# 第三个参数为卷积核大小
dst = cv2.Laplacian(gray, cv2.CV_16S, ksize = 3)
#cv2.convertScaleAbs()通过线性变换将数据转换成8位
#对于输入深度图数组,先乘以系数α,再加上偏置β,最后将结果取绝对值,并截取为8位(uint8)
Laplacian = cv2.convertScaleAbs(dst)
contour = B(Laplacian)#轮廓处理
cv2.imshow("Result",contour)
#当cv2.waitKey的参数delay大于0时,在delay时间内等待用户按键触发
#如果用户没有按下键,则继续等待下一个delay时间(循环),直到用户按键触发,退出程序
key = cv2.waitKey(50) & 0xFF
#按Q退出
if key == ord('q'):
break
cap.release()#释放摄像头
cv2.destroyAllWindows()
无注释代码(主要是看着爽):
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
#肤色检测
def A(img):
YCrCb = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB)
(y,cr,cb) = cv2.split(YCrCb)
cr1 = cv2.GaussianBlur(cr, (5,5), 0)
_, skin = cv2.threshold(cr1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
res = cv2.bitwise_and(img,img, mask = skin)
return res
#轮廓处理
def B(img):
h = cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
contour = h[0]
contour = sorted(contour, key = cv2.contourArea, reverse=True)
bg = np.ones(dst.shape, np.uint8) *255
ret = cv2.drawContours(bg,contour[0],-1,(0,255,0),3)
return ret
while(True):
ret, frame = cap.read()
src = cv2.resize(frame,(400,350), interpolation=cv2.INTER_CUBIC)
cv2.rectangle(src, (90, 60), (300, 300 ), (0, 255, 0))
roi = src[60:300 , 90:300]
res = A(roi)
cv2.imshow("CameraCapture",roi)
gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
dst = cv2.Laplacian(gray, cv2.CV_16S, ksize = 3)
Laplacian = cv2.convertScaleAbs(dst)
contour = B(Laplacian)
cv2.imshow("Result",contour)
key = cv2.waitKey(50) & 0xFF
if key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
运行结果(人脸轮廓也能被检测出来):
注意:测试的时候不要有手和脸或者其他物体一同出现在镜头前,这样会互相干扰,会检测出一个“四不像”,效果很差,最好就一个较干净的背景和手一同出现。
相关参考博客:
(6条消息) cv2.VideoCapture读取视频或摄像头,并进行保存帧图像或视频_AI算法联盟-CSDN博客_cv2.videocapturehttps://blog.csdn.net/weixin_40922285/article/details/102967331(6条消息) cv2.waitKey的入门级理解_山上有强强的博客-CSDN博客_cv2.waitkeyhttps://blog.csdn.net/weixin_44049693/article/details/106271643(6条消息) opencv中cv2.waitkey()参数详解_csdn_bajie-CSDN博客https://blog.csdn.net/qq_38132105/article/details/104470598(6条消息) OpenCV之拉普拉斯算子:Laplacian()函数_xddwz的博客-CSDN博客_laplacian算子https://blog.csdn.net/xddwz/article/details/111614803(6条消息) 颜色空间变换你使用过吗?你知道常用的颜色空间有哪些吗?_zone_chan的博客-CSDN博客https://blog.csdn.net/weixin_38646522/article/details/116592390(6条消息) 【opencv图像处理】图片通道的拆分——cv2.split_chuwangji7072的博客-CSDN博客https://blog.csdn.net/chuwangji7072/article/details/100906166(6条消息) cv2.bitwise_and()算法详解_lukas_ten的博客-CSDN博客https://blog.csdn.net/lukas_ten/article/details/115149086(6条消息) OPENCV学习之findContours()轮廓检索模式区别_ 想想叫啥名的博客-CSDN博客https://blog.csdn.net/qq_35239859/article/details/99676501?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163797492316780255294749%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=163797492316780255294749&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-99676501.pc_search_mgc_flag&utm_term=%E8%BD%AE%E5%BB%93%E6%A3%80%E7%B4%A2%E6%A8%A1%E5%BC%8F&spm=1018.2226.3001.4187(6条消息) Python OpenCV findContours()函数与drawContours()函数用法_dz4543的博客-CSDN博客https://blog.csdn.net/dz4543/article/details/80655067?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163797570816780366515948%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163797570816780366515948&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-80655067.pc_search_mgc_flag&utm_term=cv2.drawcontours%28%29%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E&spm=1018.2226.3001.4187