【MindStudio训练营第一季】使用MindX开发的人脸情绪识别应用FacialExpressionRecognition代码简析
收藏回复举报
【MindStudio训练营第一季】使用MindX开发的人脸情绪识别应用FacialExpressionRecognition代码简析
发表于2022-12-08 14:30:55
0 查看

完成了应用主体的pipeline之后,在main.py中只需要补充少量代码即可完成应用了。相比直接使用acl库去调用昇腾的计算资源实现应用功能,这种方式实现应用的代码量上要少很多,当然这也是有代价的,高度封装简单易用的代价就是牺牲了一定的灵活性和代码可见度。

先看main函数

首先是实例化了一个StreamManagerApi的类,这个类用于对流程的基本管理:加载流程配置、创建流程、向流程上发送数据、获得执行结果等,这个程序基本都依赖这个类进行控制。创建了对象之后需要对这个对象进行初始化,可以看到调用了InitManager()函数。

初始化后,加载我们之前创建的pipeline,这一步相当于把应用的功能放到了StreamManagerApi创建的stream中,接下来只要送入对应的图片数据即可开始推理

pipeline_path = b"./pipeline/facial_expression_recognition.pipeline"
ret = streamManagerApi.CreateMultipleStreamsFromFile(pipeline_path)

使用io函数直接打开并读取图片文件内容,实例化一个MxdataInput类,将数据送给它的data成员,通过SendData将数据送入StreamManagerApi去执行应用

dataInput = MxDataInput()
try
    with open(img_path, 'rb') as f:
        dataInput.data = f.read()
except:
    print("No such image")
    exit()
ret = streamManagerApi.SendData(streamName, inPluginId, dataInput)

到这里其实推理实际执行、对硬件资源的调度和使用就已经开始了,只需要通过一定的接口把结果取出来即可,获取结果使用的是GetProtobuf,这个函数是阻塞的,直到获取到了结果才会返回,这样可以保证能取到结果。通过一个简单的计时看到从SendData到GetProtobuf结束耗时约9ms,还是相当快的速度。

为了取出结果,我们需要创建一个类似c++标准库的数据结构StringVector,这个数据结构的定义在StreamManagerApi中,这个数据结构的作用应该是保存一些插件的名称,作为下面的GetProtobuf函数的第三个输入参数,获取到指定插件的输出,文档提到函数的该参数为一个bytes list,所以存入vector的字符串应该为byte格式,在字符串前加一个小写的b就表示是byte格式。

keyVec = StringVector()
keyVec.push_back(b"mxpi_imagedecoder0") # 0.解码原图
keyVec.push_back(b"mxpi_distributor0_0") # 1.人脸位置
keyVec.push_back(b"mxpi_tensorinfer1") # 2.情绪分类结果
infer_result = streamManagerApi.GetProtobuf(streamName, 0, keyVec)

返回类型是一个list,infer_result的三个元素就分别是三个插件的输出,最后使用opencv在解码的原图上绘制一下检测的四个角和情绪分类结果,存为文件即可。

由于StreamManagerApi实际上是封装了acl计算库的部分接口,所以初始化的过程中也包含了acl的初始化,初始化的过程中申请的资源就应该在应用结束时去初始化。

streamManagerApi.DestroyAllStreams()

至此整个应用的流程就结束了,可以看到,实际需要编写的只有保存结果进行可视化的这部分代码,大部分的功能都在pipeline中得到实现了,只需要按照文档按顺序去申请资源,加载文件,送入数据,释放资源就可以完成应用的开发。

看下结果,正确识别了

cke_15817.jpeg

本帖最后由 匿名用户2022/12/08 14:55:52 编辑

我要发帖子