【人工智能实验室】第四次培训之手势识别

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

Guess you like

Origin blog.csdn.net/Wendy030/article/details/121545394