分析视频中人物的表情python

参考视频来自哔哩哔哩up:小黑黑讲AI

https://b23.tv/owwJjs4

测试视频取自哔哩哔哩up:小阿森bb

https://b23.tv/xTIHH8i

 


动因:上篇文章说想分析自己不喜欢的演员的面部表情,然后我就开始做,但是没有用那个演员来做测试,而是用了我自己和一个很喜欢的baby做测试,世界应该多一些美好!阿彼真的很可爱!现在,就开始说一下过程吧!


一、deepface库的配置

参考视频可以看到up使用了deepface库,在下载deepface后opencv也跟随着下载完毕了。

在pycharm的terminal直接使用下面代码会出现下载一半就报错的问题。一开始是版本问题,更新后继续下载还是一直报错,显示time out。应该是直接在外网下载太慢了。

pip install deepface

所以使用镜像下载

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple deepface

 参考文章:https://zhuanlan.zhihu.com/p/641831098

如果完全按照视频里面的conda我会报错,没有这个配置,如果报错的也可以像我一样直接安装,反正是可以运行的。 


二、编写代码

我不太会使用github,所以没有办法像视频评论区的网友说的那样去找源代码,我就直接把视频里面的代码自己打上去了(因为代码不长)

这边附上我对着视频搞上去的代码,代码来源我就标视频吧,因为我也不知道up的代码来自哪里。打上去的时候有一部分出入:

#分析视频中人物表情
import cv2
from deepface import DeepFace
#简单测试,图片版本
# result = DeepFace.analyze(img_path="E:\\study\\test.jpg",
#                           actions=["emotion"])
# print(result)

input_video = "E:\\study\\Pythonstudy\\test\\abi.mp4"#设置待分析视频的路径
output_video ="E:\\study\\Pythonstudy\\test\\emotion.mp4"#分析结果视频

#使用opencv的videocapture接口,打开视频文件
#cap用于从视频文件或者摄像头中捕获视频帧
cap = cv2.VideoCapture(input_video)

fps = int(cap.get(cv2.CAP_PROP_FPS))#获取视频帧的速率
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))#获取视频帧的宽度
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))#获取视频帧的高度

#定义视频编解码器,指定视频文件的编码格式
#XVID是一个流行的MPEG-4的视频编解码器
fourcc = cv2.VideoWriter.fourcc('X', 'V', 'I', 'D')#老版本是_fourcc,所以一直报错
out = cv2.VideoWriter(output_video,#输出视频地址
                      fourcc,#视频编码器
                      fps, (frame_width, frame_height))#视频帧参数
#通过返回的out,可以将处理后的视频帧保存到输出文件中

frame_cnt=0#当前正在处理的帧
emodict=dict()#识别出情绪的结果

while cap.isOpened():#进入视频分析循环
    ret, frame = cap.read()#读取当前视频帧
    #如果返回值ret不是真,说明视频结束了
    if not ret:
        break#跳出循环
# 对当前帧分析,识别出当前视频帧中人物的表情
# 需要将enforce_detection设置为False
# 也就是不强制识别出人脸,否则如果没有识别到人脸就会抛出异常
    result = DeepFace.analyze(img_path=frame,
                          actions=['emotion'],
                          enforce_detection=False)

#获取结果中强度最高的情感,保存在emotion中
    emotion = result[0]['dominant_emotion']
#面部区域的位置和宽高保存在x,y,w和h中
    x, y, w, h = result[0]['region'].values()
    frame_cnt+=1#记录已经计算的帧数
#打印该帧是视频的第几帧,和这一帧对应的表情结果
    print("frame %d : %s" % (frame_cnt, emotion))

#使用字典emodict,记录每种表情的数量
    if emotion not in emodict:
        emodict[emotion] = 0
    emodict[emotion] += 1

#调用cv2.rectangle,将帧frame中的面部区域使用矩形进行框选
    cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 5)
#调用cv2.putText,将表情结果标记在矩形框的旁边
    cv2.putText(frame, emotion, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 0), 5)
#调用out.write,将标记好的帧frame保存在输出视频中
    out.write(frame)

#打印保存表情统计结果的字典emodict
print("")
print("emotion statistics:")
print("total frame : %d"%(frame_cnt))
for emotion in emodict:
    ratio = emodict[emotion]*1.0/frame_cnt*100
    print(f"{emotion:<10}frame num: emodict[emotion]:<5 ratio={ratio}")
cap.release()
out.release()

可以看到,代码中第一段被我注释掉了,那一段感兴趣的可以取消注释试着运行,用于图片人物表情分析。主要是做测试的。这里就不展示了。

代码我也看不太懂,反正就是调用各种库然后分析视频帧人物的表情,最后保存起来,感兴趣的可以搜一下各个库的使用,我太懒了就懒得搜了。唯一需要注意的点就是,如果出现了:“AttributeError: 'NoneType' object has no attribute 'shape'”这样的报错,大概率是你的视频路径里面包含了中文,参考解决方案:http://t.csdnimg.cn/5kycu


三、运行结果 

对话框会返回每一帧的分析结果。

63d741bf54144e309853899efd583089.png最后还会返回结果字典:

0554858d1dcc4a65a65d64c60c99a189.png其实按我的分析,那段视频99%都是开心,可能因为人物的面部侧过去了,所以分析的有点出入。我自己录制的视频里全部是正脸分析就比较准确,至于那段报错,我也不知道为啥,我试着改了一下,把fourcc改成了mp4v后还是会继续报错,如果有人能帮我解答这个问题就好了。

原视频好像没法插入,那就只能展示一下截图了。

原视频截图:

b0978446d6ca45d6888f5ba049bf0ad5.png

 运行后生成视频截图:

e23702d29eb043ddb821a545e077cb2e.png

超级可爱的好吗?

我感觉opencv是不是对baby的表情分析有问题,它好像有时候把笑脸识别成了sad,不清楚为什么。


四、问题与反思 

因为不想深究opencv的运行逻辑,所以直接使用后的结果让我有点摸不着头脑,不过我也只是想测试一下。

在家里实在是太无聊了,所以昨天就直接买票回了学校,就是说在动车上搞的代码真的存在很多问题,昨天晚上一直报错差点让我心态炸裂,主要的问题就是缩进,一开始因为缩进有问题,就是代码里面break后的一大串都是在循环内的,今早才发现我把它们弄到循环外了,所以一直运行错误。成功的那一刻真的很开心!

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值