-
一直返回这个但APIPost可以正常获取
-
前言 在之前的这篇博客中,简要介绍了BiFPN的原理,以及YOLOv5作者如何结合BiFPN:【魔改YOLOv5-6.x(中)】:加入ACON激活函数、CBAM和CA注意力机制、加权双向特征金字塔BiFPN 本文将尝试进一步结合BiFPN,主要参考自:YOLOv5结合BiFPN 修改yaml文件(以yolov5s为例) 只修改一处 本文以yolov5s.yaml为例进行修改,修改模型配置文件时要注意以下几点: 这里的yaml文件只修改了一处,也就是将19层的Concat换成了BiFPN_Add,要想修改其他层的Concat,可以类比进行修改 BiFPN_Add本质是add操作,不是concat操作,因此,BiFPN_Add的各个输入层要求大小完全一致(通道数、feature map大小等),因此,这里要修改之前的参数[-1, 13, 6],来满足这个要求: -1层就是上一层的输出,原来上一层的输出channel数为256,这里改成512 13层就是这里[-1, 3, C3, [512, False]], # 13 这样修改后,BiFPN_Add各个输入大小都是[bs,256,40,40] 最后BiFPN_Add后面的参数层设置为[256, 256]也就是输入输出channel数都是256 # YOLOv5 🚀 by Ultralytics, GPL-3.0 license # Parameters nc: 80 # number of classes depth_multiple: 0.33 # model depth multiple width_multiple: 0.50 # layer channel multiple anchors: - [10,13, 16,30, 33,23] # P3/8 - [30,61, 62,45, 59,119] # P4/16 - [116,90, 156,198, 373,326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 3, C3, [128]], [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 6, C3, [256]], [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 9, C3, [512]], [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 3, C3, [1024]], [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 BiFPN head head: [[-1, 1, Conv, [512, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 6], 1, Concat, [1]], # cat backbone P4 [-1, 3, C3, [512, False]], # 13 [-1, 1, Conv, [256, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 4], 1, Concat, [1]], # cat backbone P3 [-1, 3, C3, [256, False]], # 17 (P3/8-small) [-1, 1, Conv, [512, 3, 2]], # 为了BiFPN正确add,调整channel数 [[-1, 13, 6], 1, BiFPN_Add3, [256, 256]], # cat P4 <--- BiFPN change 注意v5s通道数是默认参数的一半 [-1, 3, C3, [512, False]], # 20 (P4/16-medium) [-1, 1, Conv, [512, 3, 2]], [[-1, 10], 1, Concat, [1]], # cat head P5 [-1, 3, C3, [1024, False]], # 23 (P5/32-large) [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] 将Concat全部换成BiFPN_Add # YOLOv5 🚀 by Ultralytics, GPL-3.0 license # Parameters nc: 80 # number of classes depth_multiple: 0.33 # model depth multiple width_multiple: 0.50 # layer channel multiple anchors: - [10,13, 16,30, 33,23] # P3/8 - [30,61, 62,45, 59,119] # P4/16 - [116,90, 156,198, 373,326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 3, C3, [128]], [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 6, C3, [256]], [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 9, C3, [512]], [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 3, C3, [1024]], [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 BiFPN head head: [[-1, 1, Conv, [512, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 6], 1, BiFPN_Add2, [256, 256]], # cat backbone P4 [-1, 3, C3, [512, False]], # 13 [-1, 1, Conv, [256, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 4], 1, BiFPN_Add2, [128, 128]], # cat backbone P3 [-1, 3, C3, [256, False]], # 17 (P3/8-small) [-1, 1, Conv, [512, 3, 2]], # 为了BiFPN正确add,调整channel数 [[-1, 13, 6], 1, BiFPN_Add3, [256, 256]], # cat P4 <--- BiFPN change 注意v5s通道数是默认参数的一半 [-1, 3, C3, [512, False]], # 20 (P4/16-medium) [-1, 1, Conv, [512, 3, 2]], [[-1, 10], 1, BiFPN_Add2, [256, 256]], # cat head P5 [-1, 3, C3, [1024, False]], # 23 (P5/32-large) [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] 打印模型参数 可以参考这篇博客:【YOLOv5-6.x】模型参数及detect层输出测试(自用),进行模型配置文件测试并查看输出结果: from n params module arguments 0 -1 1 3520 models.common.Conv [3, 32, 6, 2, 2] 1 -1 1 18560 models.common.Conv [32, 64, 3, 2] 2 -1 1 18816 models.common.C3 [64, 64, 1] 3 -1 1 73984 models.common.Conv [64, 128, 3, 2] 4 -1 2 115712 models.common.C3 [128, 128, 2] 5 -1 1 295424 models.common.Conv [128, 256, 3, 2] 6 -1 3 625152 models.common.C3 [256, 256, 3] 7 -1 1 1180672 models.common.Conv [256, 512, 3, 2] 8 -1 1 1182720 models.common.C3 [512, 512, 1] 9 -1 1 656896 models.common.SPPF [512, 512, 5] 10 -1 1 131584 models.common.Conv [512, 256, 1, 1] 11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] 12 [-1, 6] 1 65794 models.common.BiFPN_Add2 [256, 256] 13 -1 1 296448 models.common.C3 [256, 256, 1, False] 14 -1 1 33024 models.common.Conv [256, 128, 1, 1] 15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] 16 [-1, 4] 1 16514 models.common.BiFPN_Add2 [128, 128] 17 -1 1 74496 models.common.C3 [128, 128, 1, False] 18 -1 1 295424 models.common.Conv [128, 256, 3, 2] 19 [-1, 13, 6] 1 65795 models.common.BiFPN_Add3 [256, 256] 20 -1 1 296448 models.common.C3 [256, 256, 1, False] 21 -1 1 590336 models.common.Conv [256, 256, 3, 2] 22 [-1, 10] 1 65794 models.common.BiFPN_Add2 [256, 256] 23 -1 1 1051648 models.common.C3 [256, 512, 1, False] 24 [17, 20, 23] 1 229245 models.yolo.Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]] Model Summary: 278 layers, 7384006 parameters, 7384006 gradients, 17.2 GFLOPs 修改common.py 复制粘贴一下代码: # 结合BiFPN 设置可学习参数 学习不同分支的权重 # 两个分支add操作 class BiFPN_Add2(nn.Module): def __init__(self, c1, c2): super(BiFPN_Add2, self).__init__() # 设置可学习参数 nn.Parameter的作用是:将一个不可训练的类型Tensor转换成可以训练的类型parameter # 并且会向宿主模型注册该参数 成为其一部分 即model.parameters()会包含这个parameter # 从而在参数优化的时候可以自动一起优化 self.w = nn.Parameter(torch.ones(2, dtype=torch.float32), requires_grad=True) self.epsilon = 0.0001 self.conv = nn.Conv2d(c1, c2, kernel_size=1, stride=1, padding=0) self.silu = nn.SiLU() def forward(self, x): w = self.w weight = w / (torch.sum(w, dim=0) + self.epsilon) return self.conv(self.silu(weight[0] * x[0] + weight[1] * x[1])) # 三个分支add操作 class BiFPN_Add3(nn.Module): def __init__(self, c1, c2): super(BiFPN_Add3, self).__init__() self.w = nn.Parameter(torch.ones(3, dtype=torch.float32), requires_grad=True) self.epsilon = 0.0001 self.conv = nn.Conv2d(c1, c2, kernel_size=1, stride=1, padding=0) self.silu = nn.SiLU() def forward(self, x): w = self.w weight = w / (torch.sum(w, dim=0) + self.epsilon) # 将权重进行归一化 # Fast normalized fusion return self.conv(self.silu(weight[0] * x[0] + weight[1] * x[1] + weight[2] * x[2])) 修改yolo.py 在parse_model函数中找到elif m is Concat:语句,在其后面加上BiFPN_Add相关语句: elif m is Concat: c2 = sum(ch[x] for x in f) # 添加bifpn_add结构 elif m in [BiFPN_Add2, BiFPN_Add3]: c2 = max([ch[x] for x in f]) 修改train.py 1. 向优化器中添加BiFPN的权重参数 将BiFPN_Add2和BiFPN_Add3函数中定义的w参数,加入g1 g0, g1, g2 = [], [], [] # optimizer parameter groups for v in model.modules(): # hasattr: 测试指定的对象是否具有给定的属性,返回一个布尔值 if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter): # bias g2.append(v.bias) # biases if isinstance(v, nn.BatchNorm2d): # weight (no decay) g0.append(v.weight) elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter): # weight (with decay) g1.append(v.weight) # BiFPN_Concat elif isinstance(v, BiFPN_Add2) and hasattr(v, 'w') and isinstance(v.w, nn.Parameter): g1.append(v.w) elif isinstance(v, BiFPN_Add3) and hasattr(v, 'w') and isinstance(v.w, nn.Parameter): g1.append(v.w) 2. 查看BiFPN_Add层参数更新情况 想要查看BiFPN_Add层的参数更新情况,可以参考这篇博客【Pytorch】查看模型某一层的参数数值(自用),直接定位到w参数,随着模型训练输出对应的值。 References YOLOv5结合BiFPN 【论文笔记】EfficientDet(BiFPN)(2020) nn.Module、nn.Sequential和torch.nn.parameter学习笔记 ———————————————— 版权声明:本文为CSDN博主「嗜睡的篠龙」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_43799388/article/details/124091648
-
一:前言 本次人脸识别技术使用到的是级联分类器 对于级联分类器,如果想要自己训练模型可以参考这篇文章 【OpenCV】 级联分类器训练模型 【友情提示:训练对电脑的配置要求比较高,另外还需要有足够庞大的样本数据,因此,如果是研究生在导师实验室用着3090的,可以自己训练,但也要投入足够的时间进行数据采集。不过,这边为了方便大家学习,博主会在资源中分享 人脸识别训练模型 车辆识别训练模型 ,在读完这篇文章后,感兴趣的,想要学习的,欢迎自取】 二:人脸识别案例 实现步骤及完整代码 步骤1 灰度化处理 //灰度化处理 节省内存 Mat gray; cvtColor(frame,gray,CV_RGB2GRAY); 步骤2 将灰度图再次进行 行列压缩 //级联分类器比帧差法还更慢,因此,需要再将灰度图大小压缩一半左右 行列压缩 Mat smalling(cvRound(frame.rows/scale),cvRound(frame.cols/scale),CV_8UC1); //按存储大小计算 压缩方式采用线性压缩 resize(gray,smalling,smalling.size(),0,0,INTER_LINEAR); 步骤3 直方图均值化 //直方图均值化 让灰度图经过直方图函数处理 黑白分明 equalizeHist(smalling,smalling); //imshow("smalling",smalling); 步骤4 使用模型 对每一个像素点遍历 图像甄别 //调用级联分类器进行模型匹配并进行框选识别 使用模型去进行每一个像素点的遍历 vectorfaces; //使用CV_HAAR_SCALE_IMAGE算法 图像甄别 cascade.detectMultiScale(smalling,faces,1.1,2,0|CV_HAAR_SCALE_IMAGE,Size(30,30)); //绘制矩形 vector::const_iterator iter; //使用到容器迭代器进行遍历 for(iter=faces.begin();iter!=faces.end();iter++) { rectangle(frame, cvPoint(cvRound(iter->x*scale),cvRound(iter->y*scale)),//左上 cvPoint(cvRound((iter->x+iter->width)*scale),cvRound((iter->y+iter->height)*scale)),//右下 Scalar(0,255,0),2,8//颜色 像素位 ); } imshow("frame",frame); 人脸识别案例 完整代码如下: #include #include using namespace cv; using namespace std; //人脸识别 void datectFace(Mat &frame,CascadeClassifier cascade,double scale) { //灰度化处理 节省内存 Mat gray; cvtColor(frame,gray,CV_RGB2GRAY); //级联分类器比帧差法还更慢,因此,需要再将灰度图大小压缩一半左右 行列压缩 Mat smalling(cvRound(frame.rows/scale),cvRound(frame.cols/scale),CV_8UC1); //按存储大小计算 压缩方式采用线性压缩 resize(gray,smalling,smalling.size(),0,0,INTER_LINEAR); //直方图均值化 让灰度图经过直方图函数处理 黑白分明 equalizeHist(smalling,smalling); //imshow("smalling",smalling); //调用级联分类器进行模型匹配并进行框选识别 使用模型去进行每一个像素点的遍历 vectorfaces; //使用CV_HAAR_SCALE_IMAGE算法 图像甄别 cascade.detectMultiScale(smalling,faces,1.1,2,0|CV_HAAR_SCALE_IMAGE,Size(30,30)); //绘制矩形 vector::const_iterator iter; //使用到容器迭代器进行遍历 for(iter=faces.begin();iter!=faces.end();iter++) { rectangle(frame, cvPoint(cvRound(iter->x*scale),cvRound(iter->y*scale)),//左上 cvPoint(cvRound((iter->x+iter->width)*scale),cvRound((iter->y+iter->height)*scale)),//右下 Scalar(0,255,0),2,8//颜色 像素位 ); } imshow("frame",frame); } int main(int argc, char *argv[]) { //级联分类器对象 CascadeClassifier cascade; //读取级联分类器 cascade.load("D:/00000cars-face/face.xml"); Mat frame; //视频路径的获取 VideoCapture cap(0); while (cap.read(frame)) { //将读到的帧进行显示 imshow("frame",frame); //检测识别 图像 级联分类器 比例 datectFace(frame,cascade,2); waitKey(3); } return 0; } 结果测试:可对人脸框选识别 三:车辆识别案例 级联分类器 具体实现 如果对于上述的人脸识别案例 理解透彻 那么车辆识别也是一样的实现方法 只不过就是换了一个级联分类器 图像数据读取 罢了。 这边就直接给出 车辆识别案例 完整代码 #include #include using namespace cv; using namespace std; //车辆识别案例 void datectCarDaw(Mat &frame,CascadeClassifier cascade,double scale) { //灰度化处理 节省内存 Mat gray; cvtColor(frame,gray,CV_RGB2GRAY); //级联分类器比帧差法还更慢,因此,需要再将灰度图大小压缩一半左右 行列压缩 Mat smalling(cvRound(frame.rows/scale),cvRound(frame.cols/scale),CV_8UC1); //按存储大小计算 压缩方式采用线性压缩 resize(gray,smalling,smalling.size(),0,0,INTER_LINEAR); //直方图均值化 让灰度图经过直方图函数处理 黑白分明 equalizeHist(smalling,smalling); //imshow("smalling",smalling); //调用级联分类器进行模型匹配并进行框选识别 使用模型去进行每一个像素点的遍历 vectorcars; //使用CV_HAAR_SCALE_IMAGE算法 图像甄别 cascade.detectMultiScale(smalling,cars,1.1,2,0|CV_HAAR_SCALE_IMAGE,Size(30,30)); //绘制矩形 vector::const_iterator iter; //使用到容器迭代器进行遍历 for(iter=cars.begin();iter!=cars.end();iter++) { rectangle(frame, cvPoint(cvRound(iter->x*scale),cvRound(iter->y*scale)),//左上 cvPoint(cvRound((iter->x+iter->width)*scale),cvRound((iter->y+iter->height)*scale)),//右下 Scalar(0,255,0),2,8//颜色 像素位 ); } imshow("frame",frame); } int main(int argc, char *argv[]) { //级联分类器对象 CascadeClassifier cascade; //读取级联分类器 cascade.load("D:/00000cars-face/cars.xml"); Mat frame; //视频路径的获取 VideoCapture cap("D:/00000000000003jieduanshipincailliao/carMove.mp4"); while (cap.read(frame)) { //将读到的帧进行显示 imshow("frame",frame); //检测识别 图像 级联分类器 比例 datectCarDaw(frame,cascade,2); waitKey(3); } return 0; } 结果测试: 可以看出,图中汽车可以被识别框选,电动车不会被识别框选。 相比博主在上周分享的 帧差法 车辆识别 来看,本次车辆识别的准确度明显提高,因此,这种方法非常值得学习! 想了解 帧差法 车辆识别 可以阅读下面这篇文章 车辆识别 帧差法 具体步骤 手把手教学 以上,就是博主的全部内容啦!欢迎一起交流学习! ———————————————— 版权声明:本文为CSDN博主「我今年十六岁」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/m0_56051805/article/details/126188407
-
功能描述该接口用于向VCM子系统的指定人脸库中添加人脸照片。该照片中应包含指定人员的人脸图片。注意事项同一人员在人脸库的人脸图片不能超过五张。一个人脸库最大支持100万人脸。基本信息接口名称添加人脸图片v1.1接口路径/io-adapter/south/face-recognition/v1.1/face-picture/addHTTP方法POST请求参数请求参数如表1所示。表1 请求消息参数说明参数名称类型必选(M)/可选(O)位置参数含义X-HW-IDStringMHeaderROMA授权的应用ID。X-HW-APPKEYStringOHeaderROMA授权的应用的密钥。说明:如果调用侧在ROMA平台设置了白名单,该参数可不填,如果没有,该参数必填。channelStringMHeader选择的子系统渠道。由上层应用携带,供ROMA平台做路由选择。厂家无需实现。repositoryCodeStringMBody人脸库标识。“增加人脸库”接口返回的人脸库标识。imageUrlStringOBody人脸图片的URL路径与imageBase64二者选一。长度范围:不超过255个字符。imageBase64StringOBody人脸图片内容的BASE64编码的字符串。与imageUrl二者选一。Base64编码后大小不超过5M。图片为JPG/JPEG/BMP/PNG格式。imageIdStringOBody人脸图片的唯一ID,与当前图像绑定。若用户没提供,系统会生成一个。该ID长度范围为1~36位,可以包含字母、数字、中划线或者下划线,不包含其他的特殊字符。VCM不支持personIdStringMBody人脸图片所包含的人员实例的ID。一张人脸照片建议仅包含一个人员的正脸。如果照片中有多个人脸,则表示此人员实例的脸是照片中尺寸最大的那个脸。长度范围:0-9A-Fa-f,长度24个字符extensionobjectOBody扩展对象。用于携带厂家定义的特有字段。表2 extension参数说明参数名称类型必选(M)/可选(O)位置参数含义nameStringOBody人员姓名,支持中文、英文、数字和空格,首位不为特殊字符,长度[1,255]。genderStringOBody人员性别:0:男1:女-1:未知credentialTypeStringOBody证件类型:0:身份证1:护照2:学生证3:军官证4:驾照5:其他credentialNumberStringOBody证件号,支持英文、数字、(),长度[1,255]。请求样例{ "repositoryCode": "5d11c13a066b980884971778", "imageBase64": "/9j/4...", "personId": "5cf8b755066b980884970701" }响应参数响应参数如表3所示。表3 响应消息参数说明参数名称类型参数含义resultoutputs接口响应参数。成功时返回下方结果,失败或者数据为空时,不返回result内部的内容结构,仅返回null。resCodeString返回码。具体请参考“人员匹配错误码”。resMsgString返回消息。originalResInfooriginalResInfo原始响应消息。表4 outputs参数说明参数名称类型参数含义facesFaceStructure[]照片中包含的人脸结构。如果照片中包含多张人脸,则返回一个列表。表5 FaceStructure参数说明参数名称类型参数含义personIdString人脸图片所包含的人员实例的ID固定为24个字符。faceIdString人脸ID。支持1~36个字符。表6 originalResInfo参数说明参数名称类型参数含义originalResCodeString原始返回码。originalResMsgString原始返回消息。响应样例{ "result": { "faces": [ { "faceId": "5d1325f6066b980c1aa4ee6b", "personId": "5cf8b755066b980854970701" } ] }, "resCode": "0", "resMsg": "Success.", "originalResInfo": { "originalResCode": "0", "originalResMsg": "success" } }
-
在云速建站后台管理的第三方帐号登录中,能不能增加人脸识别登录配置?以解决会员实名认证的问题,
-
去年同醉,酴花下,健笔赋新词。今年君去,酴欲破,谁与醉为期。六月初夏,又是一年毕业季,喜悦总是与感伤并存:我们为迈入新的人生阶段而喜悦,也为与朝夕相处之人分别而不舍。一张毕业照,寄托着多少人的思念。对于很多人来说,有一张身穿学士服的毕业照,学生生活才算完整,它给三年、四年甚至更长时间的高校生活画上了一个圆满的句号。有创意的毕业照也常常能吸引不少人的注意,几乎每年,创意毕业照都能登上全网热搜。可是今年的毕业季却成了许多人的遗憾,出于疫情防控的需要,很多学校取消了毕业典礼,甚至封闭校园,不允许学生返校。对于毕业生来说,寒假时轻轻松松的"下个月见",却可能成为对彼此说的最后一句话。很多人说,他们可能失去了唯一一次穿学士服、拍毕业照的机会。为了弥补这样的遗憾,不少人"大显神通":有的人用PS给自己"抠"了一张毕业照,有的同学精通绘画,给自己和朋友们画了一张Q版毕业照,还有的同学把前两者结合,将自己的脸拼到了画中。但总觉得差了点什么,可能大家更想要一张"真实"的毕业照吧...于是今天,我将为大家分享,如何用AI简单而优雅地实现“云毕业照的拍摄”。首先看看效果:上传一个人的证件照,就可以很轻松地实现身穿学士服的毕业照的合成。当然,青春云毕业怎会只有一个人,当上传多张照片时,就可以实现一个多人合照的生成。如果说觉得背景有一些单调,那也没有关系!系统同样支持更换背景~大家可以在下面的网站中尝试生成自己的毕业照~http://119.3.249.156:32123/那么有小伙伴肯定会问了~这样一个毕业照生成器的工作原理是什么样的呢?接下来就跟大家分享我的设计思路和核心代码~1.图片上传在这个网站中,前端通过一个form标签,获取包括照片、性别、学科、学位等信息,传递到后端以进行毕业照的生成。2.特征提取当获得了上传的照片,就可以提取其人脸特征,以实现进一步的换脸操作。这在里我们使用的是python中的dlib库,它拥有一个人脸特征提取器,可以通过人脸上的68个特征点实现对人脸特征的采集。完成人脸特征点的提取后,我们就可以根据特征点构建一个人脸掩模,黑色的部分代表需要换脸的部分,白色的部分代表脸部以外(即不需要换脸的部分)。3.换脸整个换脸的操作是非常简单的,只要定位到学士服模板中人脸的位置,然后根据掩模做一个柏松融合,就能得到换脸之后的学士服照片了。大家可能会问,什么是柏松融合?其实很简单,举个栗子~如上图所示,这里的掩模是一个左半部分白色,右半部分黑色的矩形,这代表着将用图中橘子的右半部分替换苹果的右半部分,得到的便是如图右下角所示的一个“半苹果半橘子”的图片,其过渡部分非常自然,几乎看不出有拼接的痕迹。而实现这样合成效果的方法就是柏松融合。而我们将其用到了人脸上。4.多人合成单人的毕业照显得不那么完整,我们可以通过创建一个大的画布,将通过上述步骤生成的单人毕业照依次拼接在上面,从而实现多人毕业照的合成。5.添加背景背景添加方法和换脸类似,只是这次抠的是整个人的身体,再将纯蓝的背景更换为喜欢的照片,就能实现毕业照背景的添加。至此,整个AI毕业照的生成就彻底完成啦~当然,还有一些细节问题需要注意。比如,在进行多人毕业照合成时,涉及到一个对上传照片中每一张人脸位置的检测,目前主流的方法往往是使用神经网络进行检测,编写难度、硬件要求都比较高,因此我选择在ModelArts上直接实现,它提供了一个自动学习功能,可以一键训练人脸检测模型并在线部署。打开华为云ModelArts控制台,直接点击【自动学习】,就进入了配置界面:在选定数据集输出和输出位置之后,点击创建项目,进入到【数据标注】界面中。在数据标注界面,可以很方便地上传数据、并对通过鼠标框选的方式进行人脸数据的标注,完成数据集的标注后,点击【开始训练】按钮。对训练验证集比例、计算规格等进行配置,最后点击确定,自动人脸检测模型就会开始训练,整个训练过程会持续大约10分钟。 当训练完成时,会自动部署在线预测服务,通过调用在线服务,就可以实现人脸检测功能。 当然,在线服务不仅仅只能在网页中调用,可以通过在python代码中调用在线服务,从而实现与程序的完美结合,从而减少本地机器的负担、提高识别准确率。到这里,整个项目的分享就结束啦,欢迎大家下载附件中的源代码~一起体验“云毕业”叭!(注意哟~源代码中的在线服务service_id需要自己按照上面步骤部署~)【转载】华为云社区 author: Srius 发表于 2020/06/12 16:44:47
-
【功能模块】Atlas 200 DK外接树莓派摄像头采集人脸后,进行人脸识别的案例,请问哪里有,在gitee/samples里没有找到,麻烦您可以发下具体的链接么,不胜感激【操作步骤&问题现象】1、2、【截图信息】【日志信息】(可选,上传日志内容或者附件)
-
如何将multi_channels_rtsp中的人脸识别换成自己的识别物(cup,pencil,telephone等)?具体是在哪里改
-
# MindX SDK -- 人脸检测参考设计案例 ## 1 案例概述 ### 1.1 概要描述 在本系统中,目的是基于MindX SDK,在华为云昇腾平台上,开发端到端**实时人脸检测**的参考设计,实现**对三路视频中的人脸以及人脸关键点进行检测**的功能,达到性能要求 ### 1.2 模型介绍 本项目用到了一个模型: 用于人脸检测的Yunet模型 Yunet模型相关文件可以在此处下载:https://mindx.sdk.obs.cn-north-4.myhuaweicloud.com/mindxsdk-referenceapps%20/contrib/yunet/yunet.onnx ### 1.3 实现流程 1、基础环境: MindX SDK : 版本2.0.4 获取方式:https://www.hiascend.com/software/Mindx-sdk ubuntu : 版本:18.04 获取方式:请上ubuntu官网获取 Ascend-CANN-toolkit: 版本:5.0.4 获取方式:https://www.hiascend.com/software/cann/commercial 2、模型转换:利用atc工具完成模型转化:yunet.onxx --> yunet.om 3、业务流程编排与配置 4、开发检测后处理插件YunetPostProcess 5、python主程序代码开发 技术流程图如下: ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/13/1657676880325366760.png) ### 1.4 代码地址 > 本项目的代码地址为:https://gitee.com/ascend/mindxsdk-referenceapps/tree/master/contrib/yunet ## 2 软件方案介绍 ### 2.1 项目方案架构介绍 表2.1 系统方案中各模块功能: | 序号 | 子系统 | 功能描述 | | ---- | -------------- | ------------------------------------------------------------ | | 1 | 视频输入流 | 接收外部调用接口的输入视频路径,对视频进行拉流,并将拉去的裸流存储到缓冲区(buffer)中,并发送到下游插件。 | | 2 | 视频解码 | 用于视频解码,当前只支持H264格式。 | | 3 | 数据分发 | 对单个输入数据进行2次分发。 | | 4 | 数据缓存 | 输出时为后续处理过程创建一个线程,用于将输入数据与输出数据解耦,并创建缓存队列,存储尚未输入到下流插件的数据。 | | 5 | 图像处理 | 对解码后的YUV格式的图像进行放缩。 | | 6 | 模型推理插件 | 目标检测。 | | 7 | 模型后处理插件 | 对模型输出的张量进行后处理,得到物体类型数据。 | | 8 | 目标框转绘插件 | 物体类型转化为OSD实例 | | 9 | OSD可视化插件 | 实现对视频流的每一帧图像进行绘制。 | | 10 | 视频编码插件 | 用于将OSD可视化插件输出的图片进行视频编码,输出视频。 | ### 2.2 代码目录结构与说明 本工程名称为Yunet实时人脸检测,工程目录如下图所示: ```` ├── build.sh ├── config │ ├── face_yunet.cfg # yunet配置文件 │ └── Yunet.aippconfig # 模型转换aipp配置文件 ├── kpmain.py # 关键点信息输出代码 ├── main.py # 单路视频输出代码 ├── test.py # 三路后处理性能测试代码 ├── models │ └── Yunet.onnx ├── pipeline │ ├── InferTest.pipeline # 三路后处理性能测试pipeline │ ├── PluginTest.pipeline # 原方案插件性能测试pipeline │ ├── KPYunet.pipeline # 关键点信息输出pipeline │ └── Yunet.pipeline # 单路视频输出pipeline ├── plugin │ ├── build.sh │ ├── CMakeLists.txt │ ├── YunetPostProcess.cpp # 人脸检测框后处理代码 │ └── YunetPostProcess.h ├── plugin2 │ ├── build.sh │ ├── CMakeLists.txt │ ├── KPYunetPostProcess.cpp # 人脸关键点后处理代码 │ ├── KPYunetPostProcess.h ├── plugin3 │ ├── build.sh │ ├── CMakeLists.txt │ ├── TotalYunetPostProcess.cpp # 人脸检测框与关键点后处理代码(以供可视化) │ └── TotalYunetPostProcess.h ├── README.md └── run.sh ```` ## 3.1 环境依赖说明 环境依赖软件和版本如下表: | 软件名称 | 版本 | | :-----------: | :---------: | | ubantu | 18.04.1 LTS | | MindX SDK | 2.0.4 | | Python | 3.9.2 | | CANN | 5.0.4 | | numpy | 1.22.3 | | opencv-python | 4.5.5 | | 软件名称 | 版本 | 说明 | 使用教程 | | -------- | ----- | ------------------------------ | ------------------------------------------------------------ | | live555 | 1.09 | 实现视频转rstp进行推流 | [链接](https://gitee.com/ascend/mindxsdk-referenceapps/blob/master/docs/%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99/Live555%E7%A6%BB%E7%BA%BF%E8%A7%86%E9%A2%91%E8%BD%ACRTSP%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3.md) | | ffmpeg | 4.2.1 | 实现mp4格式视频转为264格式视频 | [链接](https://gitee.com/ascend/mindxsdk-referenceapps/blob/master/docs/%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99/pc%E7%AB%AFffmpeg%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B.md#https://ffmpeg.org/download.html) | 本项目适用于单人及多人正脸视频。对于人脸侧面视频,可以将人脸位置正确标出,但关键点信息标注准确率较低。本项目可以适用于仰卧人脸,但不适用于侧卧人脸。 特别地,在无人脸的情况下,我们在视频左上角设置了红色提示点。当左上角像素出现红色时,说明此场景没有检测出人脸。(下面给出该特殊点检测框的数据信息) ```` "MxpiObject":[{"classVec":[{"classId":3,"className":"","confidence":0,"headerVec":[]}],"x0":0,"x1":0,"y0":0,"y1":0}] ```` 另外,本项目要求输入视频为1920*1080 25fps视频,不支持25帧率以上视频。 ### 3.2 环境搭建 在编译运行项目前,需要设置环境变量: ```bash . /usr/local/Ascend/ascend-toolkit/set_env.sh . ${SDK安装路径}/mxVision/set_env.sh export install_path=/usr/local/Ascend/ascend-toolkit/latest export PATH=${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/atc/python/site-packages/auto_tune.egg/auto_tune:${install_path}/atc/python/site-packages/schedule_search.egg export LD_LIBRARY_PATH=${install_path}/atc/lib64:$LD_LIBRARY_PATH export ASCEND_OPP_PATH=${install_path}/opp ``` 注:其中SDK安装路径${MX_SDK_HOME}替换为用户的SDK安装路径。 ### 3.3 模型转换 本项目中使用的模型是yunet模型,onnx模型可以直接[下载](https://mindx.sdk.obs.cn-north-4.myhuaweicloud.com/mindxsdk-referenceapps%20/contrib/yunet/yunet.onnx)。下载后使用模型转换工具ATC将onnx模型转换为om模型,模型转换工具相关介绍参考[链接](https://support.huaweicloud.com/tg-cannApplicationDev330/atlasatc_16_0005.html) 模型转换步骤如下: 设置ATC env:当前目录下运行 ```` export install_path=/usr/local/Ascend/ascend-toolkit/latest export PATH=/usr/local/python3/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/atc/python/site-packages/auto_tune.egg/auto_tune:${install_path}/atc/python/site-packages/schedule_search.egg:$PYTHONPATH export LD_LIBRARY_PATH=${install_path}/atc/lib64:$LD_LIBRARY_PATH export ASCEND_OPP_PATH=${install_path}/opp ```` cd到models文件夹,运行 ```` atc --framework=5 --model=yunet.onnx --output=yunet --input_format=NCHW --input_shape="input:1,3,120,160" --log=debug --soc_version=Ascend310 --insert_op_conf=../config/Yunet.aippconfig ```` 执行该命令后会在指定输出.om模型路径生成项目指定模型文件`yunet.om`。若模型转换成功则输出: ``` ATC start working now, please wait for a moment. ATC run success, welcome to the next use. ``` aipp文件配置如下: ``` aipp_op { related_input_rank : 0 src_image_size_w : 160 src_image_size_h : 120 crop : false aipp_mode: static input_format : YUV420SP_U8 csc_switch : true rbuv_swap_switch : false matrix_r0c0 : 256 matrix_r0c1 : 454 matrix_r0c2 : 0 matrix_r1c0 : 256 matrix_r1c1 : -88 matrix_r1c2 : -183 matrix_r2c0 : 256 matrix_r2c1 : 0 matrix_r2c2 : 359 input_bias_0 : 0 input_bias_1 : 128 input_bias_2 : 128 mean_chn_0 : 0 mean_chn_1 : 0 mean_chn_2 : 0 min_chn_0 : 0.0 min_chn_1 : 0.0 min_chn_2 : 0.0 var_reci_chn_0 : 1.0 var_reci_chn_1 : 1.0 var_reci_chn_2 : 1.0 } ``` ## 4 实时人脸检测流程开发实现 ### 4.1 pipeline编排 ``` mxpi_rtspsrc mxpi_videodecoder # 视频解码 mxpi_imageresize # 图像缩放 tee # 解码视频分发 mxpi_tensorinfer # 模型推理 mxpi_objectpostprocessor # 模型后处理 mxpi_object2osdinstances # osd实例化 mxpi_channelimagesstitcher # 图片合并 mxpi_channelosdcoordsconverter mxpi_opencvosd mxpi_videoencoder appsink ``` ### 4.2 实时人脸检测后处理库开发 参考分类识别模型后处理库开发。 > 参考链接:https://gitee.com/ascend/docs-openmind/blob/master/guide/mindx/sdk/tutorials/quick_start/4-2%E6%A8%A1%E5%9E%8B%E5%90%8E%E5%A4%84%E7%90%86%E5%BA%93(%E5%86%85%E7%BD%AE%E7%B1%BB%E5%9E%8B)%E5%BC%80%E5%8F%91%E8%B0%83%E8%AF%95%E6%8C%87%E5%AF%BC.md ### 4.3 主程序开发 1、初始化流管理。 2、加载视频,进行推理。 3、获取pipeline各插件输出结果,解析输出结果。 4、根据识别结果在视频中标出人脸信息 5、测试性能,获取输出视频帧率 6、销毁流 ## 5 编译与运行 `main.py`:用来生成端对端单路推理的可视化视频,以提供单路推理结果可视化的应用样例 `kpmain.py`:用来生成单路关键点后处理的数据结果(用来确保关键点类型后处理的实现成功,关键点效果看main.py的可视化结果) (`kpmain.py`在此项目中不是必须的,当前没有keypoint类型osd支持下,仅给出单路pipeline输出数据信息供参考) `test.py`:用来输出端对端三路推理的后处理结果,以检测三路推理性能是否达标 需要注意的是,本项目后处理插件支持三路视频推理的后处理,但由于mxVision-2.0.4暂不支持三路后处理输出,所以此处采取单路视频可视化和三路推理性能检测两部分,分别提供可视化应用与性能检测的功能。 1.编译后处理插件 `cd`到`plugin`目录,`mkdir`新建文件夹`build` `cd`到`build`,运行 ```` cmake .. make -j make install ```` 如果权限问题,`cd`到MindSDK安装路径的`lib/modelpostprocessors`目录,将`libyunetpostprocess.so`的权限更改为`640`。 对于`plugin2`、`plugin3`目录也同样处理。 2.`config/face_yunet.cfg` 确认权限`640`。 3.运行`main.py`程序 `cd`到根目录,运行 ```` bash run.sh ```` 最后会得到`result.264`即为输出结果 ## 6 常见问题 ### 权限问题 **问题描述:** ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/13/1657676735740192074.png) **解决方案:** cd到run包的./lib/modelpostprocessors目录,运行 ```` chmod 640 libyunetpostprocess.so ```` 对于plugin2、plugin3目录也同样处理。 ### 负荷问题 若视频解码器负荷过高则会出现以下问题: ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/13/1657676706976134205.png) ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/13/1657676761121560284.png) 导致此问题的可能原因为:视频帧率过高、视频尺寸过大或解码器正在同时解码过多其他视频 解决方案:确保三路视频都为1920*1080 25fps并且减少其它任务的运行 ## 7 参考链接 > Yunet模型,参考链接:https://github.com/ShiqiYu/libfacedetection
-
# 基于STM32单片机设计的红外测温仪(带人脸检测) 由于医学发展的需要,在很多情况下,一般的温度计己经满足不了快速而又准确的测温要求,例如:车站、地铁、机场等人口密度较大的地方进行人体温度测量。 当前设计的这款红外测温仪由测温硬件+上位机软件组合而成,主要用在地铁、车站入口等地方,可以准确识别人脸进行测温,如果有人温度超标会进行语音提示并且保存当前人脸照片。 ## 1、 硬件选型与设计思路 ### (1). 设备端 主控单片机采用STM32F103C8T6,人体测温功能采用非接触式红外测温模块。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/6/1657088443080712875.png) ### (2). 上位机设计思路 上位机采用Qt5设计,Qt5是一套基于C++语言的跨平台软件库,性能非常强大,目前桌面端很多主流的软件都是采用QT开发。比如: 金山办公旗下的-WPS,字节跳动旗下的-剪映,暴雪娱乐公司旗下-多款游戏登录器等等。Qt在车联网领域用的也非常多,比如,哈佛,特斯拉,比亚迪等等很多车的中控屏整个系统都是采用Qt设计。 在测温项目里,上位机与STM32之间采用串口协议进行通信,上位机可以打开笔记本电脑默认的摄像头,进行人脸检测;当检测到人脸时,控制STM32测量当前人体的实时温度实时,再将温度传递到上位机显示;当温度正常时,上位机上显示绿色的提示字样“温度正常”,并有语音播报,语音播报的声音使用笔记本自带的声卡发出。如果温度过高,上位机显示红色提示字样“温度异常,请重新测量”,并有语音播报提示。温度过高时,会自动将当前人脸拍照留存,照片存放在当前软件目录下的“face”目录里,文件的命名规则是“38.8_2022-01-05-22-12-34.jpg”,其中38.8表示温度值,后面是日期(年月日时分秒)。 ### (3) 上位机运行效果 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/6/1657088458540921923.png) ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20227/6/1657088467253561881.png) 上位机需要连接STM32设备之后才可以获取温度数据,点击软件上的打开摄像头按钮,开启摄像头,让检测到人脸时,下面会显示当前测量的温度。如果没有连接STM32设备,那么默认会显示一个正常的固定温度值。界面上右边红色的字,表示当前处理一帧图像的耗时时间,电脑性能越好,检测速度越快。 ### (4) 拿到可执行文件之后如何运行? 先解压压缩包,进入“测温仪上位机-可执行文件”目录,将“haarcascade_frontalface_alt2.xml”拷贝到C盘根目录。 ![img](https://bbs-img.huaweicloud.com/blogs/img/16e6b1.png) ![img](https://bbs-img.huaweicloud.com/blogs/img/17a28c.png) 然后双击“FaceTemperatureCheck.exe”运行程序。 ![img](https://bbs-img.huaweicloud.com/blogs/img/18c1fe.png) 未连接设备,也可以打开摄像头检测人脸,只不过温度值是一个固定的正常温度值范围。 ## 二、上位机设计 ## 2.1 安装编译环境 如果需要自己编译运行源代码,需要先安装Qt5开发环境。 下载地址: https://download.qt.io/official_releases/qt/5.12/5.12.0/ ![img](https://bbs-img.huaweicloud.com/blogs/img/197e29.png) 下载之后,先将电脑网络断掉(不然会提示要求输入QT的账号),然后双击安装包进行安装。 安装可以只需要选择一个MinGW 32位编译器就够用了,详情看下面截图,选择“MinGW 7.3.0 32-bit”后,就点击下一步,然后等待安装完成即可。 ![img](https://bbs-img.huaweicloud.com/blogs/img/1b27e0.png) ## 2.2 软件代码整体效果 如果需要完整的工程,可以在这里去下载:https://download.csdn.net/download/xiaolong1126626497/85892490 ![img](https://bbs-img.huaweicloud.com/blogs/img/1d3671.png) 打开工程后(工程文件的后缀是xxx.pro),点击左下角的绿色三角形按钮就可以编译运行程序。 ![img](https://bbs-img.huaweicloud.com/blogs/img/206514.png) ## 2.3 UI设计界面 ![img](https://bbs-img.huaweicloud.com/blogs/img/239444.png) ## 2.4 人脸检测核心代码 ```cpp //人脸检测代码 bool ImageHandle::opencv_face(QImage qImage) { bool check_flag=0; QTime time; time.start(); static CvMemStorage* storage = nullptr; static CvHaarClassifierCascade* cascade = nullptr; //模型文件路径 QString face_model_file = QCoreApplication::applicationDirPath()+"/"+FACE_MODEL_FILE; //加载分类器:正面脸检测 cascade = (CvHaarClassifierCascade*)cvLoad(face_model_file.toUtf8().data(), 0, 0, 0 ); if(!cascade) { qDebug()"分类器加载错误.\n"; return check_flag; } //创建内存空间 storage = cvCreateMemStorage(0); //加载需要检测的图片 IplImage* img = QImageToIplImage(&qImage); if(img ==nullptr ) { qDebug()"图片加载错误.\n"; return check_flag; } double scale=1.2; //创建图像首地址,并分配存储空间 IplImage* gray = cvCreateImage(cvSize(img->width,img->height),8,1); //创建图像首地址,并分配存储空间 IplImage* small_img=cvCreateImage(cvSize(cvRound(img->width/scale),cvRound(img->height/scale)),8,1); cvCvtColor(img,gray, CV_BGR2GRAY); cvResize(gray, small_img, CV_INTER_LINEAR); cvEqualizeHist(small_img,small_img); //直方图均衡 /* * 指定相应的人脸特征检测分类器,就可以检测出图片中所有的人脸,并将检测到的人脸通过矩形的方式返回。 * 总共有8个参数,函数说明: 参数1:表示输入图像,尽量使用灰度图以加快检测速度。 参数2:表示Haar特征分类器,可以用cvLoad()函数来从磁盘中加载xml文件作为Haar特征分类器。 参数3:用来存储检测到的候选目标的内存缓存区域。 参数4:表示在前后两次相继的扫描中,搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10% 参数5:表示构成检测目标的相邻矩形的最小个数(默认为3个)。如果组成检测目标的小矩形的个数和小于 min_neighbors - 1 都会被排除。如果min_neighbors 为 0, 则函数不做任何操作就返回所有的被检候选矩形框,这种设定值一般用在用户自定义对检测结果的组合程序上。 参数6:要么使用默认值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果设置为CV_HAAR_DO_CANNY_PRUNING,那么函数将会使用Canny边缘检测来排除边缘过多或过少的区域,因此这些区域通常不会是人脸所在区域。 参数7:表示检测窗口的最小值,一般设置为默认即可。 参数8:表示检测窗口的最大值,一般设置为默认即可。 函数返回值:函数将返回CvSeq对象,该对象包含一系列CvRect表示检测到的人脸矩形。 */ CvSeq* objects = cvHaarDetectObjects(small_img, cascade, storage, 1.1, 3, 0/*CV_HAAR_DO_CANNY_PRUNING*/, cvSize(50,50)/*大小决定了检测时消耗的时间多少*/); qDebug()"人脸数量:"total; //遍历找到对象和周围画盒 QPainter painter(&qImage);//构建 QPainter 绘图对象 QPen pen; pen.setColor(Qt::blue); //画笔颜色 pen.setWidth(5); //画笔宽度 painter.setPen(pen); //设置画笔 CvRect *max=nullptr; for(int i=0;i(objects->total);++i) { //得到人脸的坐标位置和宽度高度信息 CvRect* r=(CvRect*)cvGetSeqElem(objects,i); if(max==nullptr)max=r; else { if(r->width > max->width || r->height > max->height) { max=r; } } } //如果找到最大的目标脸 if(max!=nullptr) { check_flag=true; //将人脸区域绘制矩形圈起来 painter.drawRect(max->x*scale,max->y*scale,max->width*scale,max->height*scale); } cvReleaseImage(&gray); //释放图片内存 cvReleaseImage(&small_img); //释放图片内存 cvReleaseHaarClassifierCascade(&cascade); //释放内存-->分类器 cvReleaseMemStorage(&objects->storage); //释放内存-->检测出图片中所有的人脸 //释放图片 cvReleaseImage(&img); qint32 time_ms=0; time_ms=time.elapsed(); //耗时时间 emit ss_log_text(QString("%1").arg(time_ms)); //保存结果 m_image=qImage.copy(); return check_flag; } ``` ## 2.5 配置文件(修改参数-很重要) ![img](https://bbs-img.huaweicloud.com/blogs/img/2fe364.png) 参数说明: 如果电脑上有多个摄像头,可以修改配置文件里的摄像头编号,具体的数量在程序启动时会自动查询,通过打印代码输出到终端。 如果自己第一次编译运行源码,运行之后, (1)需要将软件源码目录下的“haarcascade_frontalface_alt2.xml” 文件拷贝到C盘根目录,或者其他非中文目录下,具体路径可以在配置文件里修改,默认就是C盘根目录。 (2)需要将软件源码目录下的“OpenCV-MinGW-Build-OpenCV-3.4.7\x86\mingw\bin”目录里所有文件拷贝到,生成的程序执行文件同级目录下。 这样才能保证程序可以正常运行。 报警温度的阀值范围,也可以自行更改,在配置文件里有说明。 ## 2.6 语音提示文件与背景图 语音提示文件,背景图是通过资源文件加载的。 源文件存放在,源代码的“FaceTemperatureCheck\res”目录下。 ![img](https://bbs-img.huaweicloud.com/blogs/img/32b8d5.png) 自己也可以自行替换,重新编译程序即可生效。 ## 2.7 语音播报与图像显示处理代码 ```cpp //图像处理的结果 void Widget::slot_HandleImage(bool flag,QImage image) { bool temp_state=0; //检测到人脸 if(flag) { //判断温度是否正常 if(current_tempMIN_TEMP) { temp_state=true; //显示温度正常 ui->label_temp->setStyleSheet("color: rgb(0, 255, 127);font: 20pt \"Arial\";"); ui->label_temp->setText(QString("%1℃").arg(current_temp)); } else //语音播报,温度异常 { temp_state=false; //显示温度异常 ui->label_temp->setStyleSheet("color: rgb(255, 0, 0);font: 20pt \"Arial\";"); ui->label_temp->setText(QString("%1℃").arg(current_temp)); } //获取当前ms时间 long long currentTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); //判断时间间隔是否到达 if(currentTime-old_currentTime>AUDIO_RATE_MS) { //更改当前时间 old_currentTime=currentTime; //温度正常 if(temp_state) { //语音播报,温度正常 QSound::play(":/res/ok.wav"); } //温度异常 else { //语音播报,温度异常 QSound::play(":/res/error.wav"); //拍照留存 QString dir_str = QCoreApplication::applicationDirPath()+"/face"; //检查目录是否存在,若不存在则新建 QDir dir; if (!dir.exists(dir_str)) { bool res = dir.mkpath(dir_str); qDebug() "新建目录状态:" res; } //目录存在就保存图片 QDir dir2; if (dir2.exists(dir_str)) { //拼接名称 QDateTime dateTime(QDateTime::currentDateTime()); //时间效果: 2020-03-05 16:25::04 周一 QString qStr=QString("%1/%2_").arg(dir_str).arg(current_temp); qStr+=dateTime.toString("yyyy-MM-dd-hh-mm-ss-ddd"); image.save(qStr+".jpg"); } } } } else //不显示温度 { ui->label_temp->setStyleSheet("color: rgb(0, 255, 127);font: 20pt \"Arial\";"); ui->label_temp->setText("----"); } //处理图像的结果画面 ui->widget_player->slotGetOneFrame(image); } ``` ## 2.8 STM32的温度接收处理代码 ```cpp //刷新串口端口 void Widget::on_pushButton_flush_uart_clicked() { QList UartInfoList=QSerialPortInfo::availablePorts(); //获取可用串口端口信息 ui->comboBox_ComSelect->clear(); if(UartInfoList.count()>0) { for(int i=0;i/如果当前串口 COM 口忙就返回真,否则返回假 { QString info=UartInfoList.at(i).portName(); info+="(占用)"; ui->comboBox_ComSelect->addItem(info); //添加新的条目选项 } else { ui->comboBox_ComSelect->addItem(UartInfoList.at(i).portName()); //添加新的条目选项 } } } else { ui->comboBox_ComSelect->addItem("无可用COM口"); //添加新的条目选项 } } //连接测温设备 void Widget::on_pushButton_OpenUart_clicked() { if(ui->pushButton_OpenUart->text()=="连接测温设备") //打开串口 { ui->pushButton_OpenUart->setText("断开连接"); /*配置串口的信息*/ UART_Config->setPortName(ui->comboBox_ComSelect->currentText()); //COM的名称 if(!(UART_Config->open(QIODevice::ReadWrite))) //打开的属性权限 { QMessageBox::warning(this, tr("状态提示"), tr("设备连接失败!\n请选择正确的COM口"), QMessageBox::Ok); ui->pushButton_OpenUart->setText("连接测温设备"); return; } } else //关闭串口 { ui->pushButton_OpenUart->setText("连接测温设备"); /*关闭串口-*/ UART_Config->clear(QSerialPort::AllDirections); UART_Config->close(); } } //读信号 void Widget::ReadUasrtData() { /*返回可读的字节数*/ if(UART_Config->bytesAvailable()=0) { return; } /*定义字节数组*/ QByteArray rx_data; /*读取串口缓冲区所有的数据*/ rx_data=UART_Config->readAll(); //转换温度 current_temp=rx_data.toDouble(); } ```
-
像华为云客服,华为云OBS等都以插件形式方便用户,可以不可以将华为云的人脸识别功能和文字识别功能做成插件,比如会员实名认证,刷脸登录都会用到。
-
在后台支付设置里能不能增加支付方式种类,除了扫码方式外,可不可以增加人脸支付和指纹支付?还有就是在第三方登录方式中除了QQ,微博,微信三种外可不可以增加人脸识别和指纹登录?
-
在后台支付设置里能不能增加支付方式种类,除了扫码方式外,可不可以增加人脸支付和指纹支付?还有就是在第三方登录方式中除了QQ,微博,微信三种外可不可以增加人脸识别和指纹登录?
-
又找不到包的警告,求助!!!
-
# MindX SDK+CenterFace动态分辨率模型推理 ## 1 介绍 [MindX SDK](https://gitee.com/link?target=https%3A%2F%2Fwww.hiascend.com%2Fsoftware%2Fmindx-sdk) 是华为推出的软件开发套件(SDK),提供极简易用、高性能的API和工具,助力昇腾AI处理器赋能各种应用场景。对于一个训练好的模型,在Mind SDK上仅需在stream流的pipeline配置文件中简单配置几行,便可使用内置的插件实现模型的前处理和后处理,完成常见的推理任务。本文将介绍如何在MindX SDK框架上实现动态分辨率模型的推理。(代码地址:https://gitee.com/ascend/mindxsdk-referenceapps/tree/master/contrib/CenterFace) **动态分辨率:**指模型转化为om格式在MindX SDK上进行推理时,通常模型输入的图片大小一般固定为ATC工具转化时所设定的值。如果所有尺寸的图片都缩放至同一大小,对于尺寸与模型输入差距过大的图片,模型推理的效果难以符合预期。因此在使用ATC工具转化模型时,开启动态分辨率的功能,配置多个档位以适配常见的图片尺寸,模型推理时根据图片大小选用合适的档位。 本案例推理采用[CenterFace](https://github.com/Star-Clouds/CenterFace)(一个轻量化的人脸检测模型,同时实现了人脸检测+关键点检测),考虑到API中已有的后处理插件基类,以及输出结果的特殊性,开发了两个后处理插件,其余均使用框架自带插件。 本文将涵盖以下内容:*模型推理流程*、*动态分辨率模型转换*、*模型后处理开发介绍*。 ## 2 开发工具准备 > MindX SDK模型开发须使用本地IDE工具连接昇腾服务器,使用本教程前,请确保以下环境正确安装。 - 在昇腾机器上安装MindX SDK,MindX SDK软件包安装[参考链接](https://support.huawei.com/enterprise/zh/doc/EDOC1100209684?section=j00h) - Cmake - 本地C++开发环境搭建,以下演示使用[CLion](https://www.jetbrains.com/clion/download/download-thanks.html?platform=windows) - 远程SSH工具,如MobaXterm,xshell,final shell(以下演示使用MobaXterm) ## 3 开发环境配置 请参考官方技术文档:[IDE开发环境搭建](https://gitee.com/ascend/docs-openmind/blob/master/guide/mindx/sdk/tutorials/quick_start/1-2IDE开发环境搭建.md#/ascend/docs-openmind/blob/master/guide/mindx/sdk/tutorials/quick_start/Cmake介绍.md) ## 4 开发流程介绍 在MinX SDK上实现模型推理,通常包含以下几个步骤: - 准备好用于推理的模型。 - 使用ATC工具转换为om模型(转换过程根据模型的要求配置aipp做前处理)。 - 根据业务需求,编排steam流,编写主函数。 - 根据需要开发插件或后处理插件。 ## 5 开发 ### 5.1 准备模型 从CenterFace官方仓下载onnx模型([github下载链接](https://gitee.com/link?target=https%3A%2F%2Fgithub.com%2FStar-Clouds%2FCenterFace%2Fblob%2Fmaster%2Fmodels%2Fonnx%2Fcenterface.onnx)),无法访问github请使用[备用链接](https://mindx.sdk.obs.cn-north-4.myhuaweicloud.com/mindxsdk-referenceapps%20/contrib/CenterFaceWithDynamicResolution/centerface_offical.onnx)。 如果你的模型是其它格式,同样可以通过以下工具转化为MindX SDK使用的模型格式。 ### 5.2 动态分辨率模型转换 转换模型之前需要在昇腾服务器上安装和配置好ATC模型转换工具(模型转换工具相关介绍参考[链接](https://gitee.com/link?target=https%3A%2F%2Fsupport.huaweicloud.com%2Ftg-cannApplicationDev330%2Fatlasatc_16_0005.html))。如果服务器上已经具备ATC工具,但未配置环境变量,可参考如下配置: ```bash export install_path=/usr/local/Ascend/ascend-toolkit/latest export PATH=/usr/local/python3/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/atc/python/site-packages/auto_tune.egg/auto_tune:${install_path}/atc/python/site-packages/schedule_search.egg export LD_LIBRARY_PATH=${install_path}/atc/lib64:$LD_LIBRARY_PATH export ASCEND_OPP_PATH=${install_path}/opp ``` 接着获取模型输入节点的名称,下载Netron,安装后使用Netron打开onnx模型 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654843579757448142.png) 可以看到模型的输入节点名称为:`input.1` 使用SSH工具附带的ftp功能把下载好的onnx模型上传至昇腾服务器,cd进入模型存放的目录,执行如下命令: ```bash atc --model=centerface_offical.onnx --output=centerface_offical --dynamic_image_size="768,1024;800,800;1024,768;864,1120;1120,864;960,1216;1216,960;1056,1312;1312,1056;1152,1408;1408,1152;1248,1504;1504,1248;1344,1600;1600,1344;1440,1696;1696,1440;1536,1792;1792,1536;1632,1888;1888,1632;1728,1984;1984,1728;1824,2080;2080,1824" --soc_version=Ascend310 --input_shape="input.1:1,3,-1,-1" --input_format=NCHW --framework=5 --insert_op_conf=centerface_aipp.cfg ``` 以上命令转成具有多档位的动态分辨率模型,转成单档位可使用如下命令: ```bash atc --model=centerface_offical.onnx --output=centerface_offical --soc_version=Ascend310 --input_shape="input.1:1,3,800,800" --input_format=NCHW --framework=5 --insert_op_conf=centerface_aipp.cfg ``` 命令参数的解释如下: - --model 待转换模型存放的路径 - --output 模型输出路径及输出模型命名 - --soc_version 芯片版本 - --input_shape 模型输入节点名称和tensor形状,当配置动态分辨率属性时,图片宽高应设为-1 - --input_format 输入图片的数据格式 - --dynamic_image_size 动态分辨率属性,配置后模型可接受不同分辨率的输入 - --framework 原模型使用的框架 - --insert_op_conf aipp配置文件 > aipp配置文件为可选,作用在于对模型输入数据进行前处理,是根据模型的输入要求进行具体配置的。 > > 此处因MindX SDK图片解码器仅支持JPG图像,并且解码成YUV420sp,而CenterFace模型的输入格式为RGB888,因此配置了色域转换的相关属性。具体配置文件如下 ```yaml aipp_op{ aipp_mode: static crop: false input_format : YUV420SP_U8 #非动态分辨率请设置具体的宽高 src_image_size_h : 0 src_image_size_w : 0 csc_switch : true rbuv_swap_switch : false matrix_r0c0 : 256 matrix_r0c1 : 0 matrix_r0c2 : 359 matrix_r1c0 : 256 matrix_r1c1 : -88 matrix_r1c2 : -183 matrix_r2c0 : 256 matrix_r2c1 : 454 matrix_r2c2 : 0 input_bias_0 : 0 input_bias_1 : 128 input_bias_2 : 128 mean_chn_0 : 0 mean_chn_1 : 0 mean_chn_2 : 0 min_chn_0 : 0 min_chn_1 : 0 min_chn_2 : 0 var_reci_chn_0: 1.0 var_reci_chn_1: 1.0 var_reci_chn_2: 1.0 } ``` 开启动态分辨率属性后,经过ATC工具转化的模型,已具备接受多个分辨率输入的功能,通过修改pipeline中缩放插件的属性,即可改变模型输入的大小。 ### 5.3 项目创建与pipeline流程编排 #### 新建CLION项目 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654843536158771876.png) #### CmakeLists文件 ```cmake cmake_minimum_required(VERSION 3.10) project(CenterFace) add_compile_options(-fPIC -fstack-protector-all -g -Wl,-z,relro,-z,now,-z -pie -Wall) add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0 -Dgoogle=mindxsdk_private) set(CMAKE_BUILD_TYPE Debug) set(MX_SDK_HOME $ENV{MX_SDK_HOME}) #使用本地IDE运行请配置MX_SDK_HOME的绝对路径 if (NOT DEFINED ENV{MX_SDK_HOME}) string(REGEX REPLACE "(.*)/(.*)/(.*)/(.*)" "\\1" MX_SDK_HOME ${CMAKE_CURRENT_SOURCE_DIR}) message(STATUS "set default MX_SDK_HOME: ${MX_SDK_HOME}") else () message(STATUS "env MX_SDK_HOME: ${MX_SDK_HOME}") endif() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/") #需要用到的头文件 include_directories( ${MX_SDK_HOME}/include ${MX_SDK_HOME}/opensource/include ${MX_SDK_HOME}/opensource/include/opencv4 ) #链接的动态库 link_directories( ${MX_SDK_HOME}/lib ${MX_SDK_HOME}/opensource/lib ) add_executable(Main main.cpp ) target_link_libraries(Main glog mxbase mxpidatatype plugintoolkit streammanager cpprest mindxsdk_protobuf opencv_world ) ``` #### 主函数编写 ```C++ #include "MxBase/Log/Log.h" #include "MxBase/MemoryHelper/MemoryHelper.h" #include "MxStream/StreamManager/MxStreamManager.h" #include "opencv2/opencv.hpp" #include PostProcessBases/PostProcessDataType.h> #include #include int main(int argc, char *argv[]) { // 读取pipeline文件信息 std::string pipelineConfigPath = "pipeline配置文件路径"; std::string pipelineConfig = ReadPipelineConfig(pipelineConfigPath); if (pipelineConfig == "") { return APP_ERR_COMM_INIT_FAIL; } std::string streamName = "center_face"; // 新建一个流管理MxStreamManager对象并初始化 auto mxStreamManager = std::make_shared(); APP_ERROR ret = mxStreamManager->InitManager(); // 加载pipeline得到的信息,创建一个新的stream业务流 ret = mxStreamManager->CreateMultipleStreams(pipelineConfig); MxStream::MxstDataInput dataBuffer; // 将图片的信息读取到dataBuffer中 ret = readfile(fileName, dataBuffer); // 通过SendData函数传递输入信息到指定的工作元件模块 // streamName是pipeline文件中业务流名称;inPluginId为输入端口编号,对应输入元件的编号 ret = mxStreamManager->SendData(streamName, 0, dataBuffer); delete dataBuffer.dataPtr; // 获取Stream上后处理插件的处理结果 std::vector keyVec = {"mxpi_imagedecoder0", "mxpi_objectpostprocessor0", "mxpi_objectpostprocessor1"}; std::vector output =mxStreamManager->GetProtobuf(streamName, 0, keyVec); // mxpi_imagedecoder0图片解码插件输出信息 auto mxpiVision = std::static_pointer_cast(output[0].messagePtr); // mxpi_objectpostprocessor0 后处理插件1输出信息 auto objectList = std::static_pointer_cast(output[1].messagePtr); // mxpi_objectpostprocessor1 后处理插件2输出信息 auto keypointList = std::static_pointer_cast(output[2].messagePtr); // 把经过后处理之后的推理结果写入到图片中 SaveResult(mxpiVision, objectList, keypointList); mxStreamManager->DestroyAllStreams(); return 0; } ``` > 以上代码仅作主函数的大体逻辑展示 #### pipeline流程编排 模型的推理业务流程如下: 1. 使用StreamManager的api从外部把图片二进制数据送入appsrc插件。 2. 使用图像解码mxpi_imagedecoder对图片进行解码。 3. 通过图像缩放插件mxpi_imageresize将图形缩放至指定的分辨率档位。 4. 缩放后的图形输入模型推理插件mxpi_tensorinfer得到模型输出。 5. 把模型得到的四个输出送入两个后处理插件。 6. 人脸检测插件用来得到人脸检测框,关键点检测插件得到五个关键点。 7. 人脸检测框送入OSD可视化插件编码到原图中。 8. 最后两个后处理插件分支汇聚到appsink结束整个推理流程。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654843473547740298.png) 在pipeline的编排中,对于上图分叉的部分,使用了内置的tee插件接queue插件处理,使得两个后处理插件都能获得模型推理的输出数据。此外OSD可视化插件的输入用到了图像解码挂载的metadata,同样使用了tee插件接queue,图上并未标明。 对应的pipeline文件: ```json { "center_face": { "stream_config": { "deviceId": "0" }, "appsrc0": { "props": { "blocksize": "409600" }, "factory": "appsrc", "next": "mxpi_imagedecoder0" }, "mxpi_imagedecoder0": { "props": { "deviceId": "0" }, "factory": "mxpi_imagedecoder", "next": "mxpi_imageresizer0" }, "mxpi_imageresizer0": { "props": { "dataSource": "mxpi_imagedecoder0", "resizeHeight": "768", "resizeWidth": "1024" }, "factory": "mxpi_imageresize", "next": "tee0" }, "tee0": { "factory": "tee", "next": [ "queue0", "queue1" ] }, "queue0": { "props": { "max-size-buffers": "50" }, "factory": "queue", "next": "mxpi_tensorinfer0" }, "queue1": { "props": { "max-size-buffers": "50" }, "factory": "queue", "next": "mxpi_opencvosd0:0" }, "tee1": { "factory": "tee", "next": [ "queue2", "queue3" ] }, "queue2": { "props": { "max-size-buffers": "50" }, "factory": "queue", "next": "mxpi_objectpostprocessor0" }, "queue3": { "props": { "max-size-buffers": "50" }, "factory": "queue", "next": "mxpi_objectpostprocessor1" }, "mxpi_tensorinfer0": { "props": { "dataSource": "mxpi_imageresizer0", "modelPath": "../model/centerface_offical.om" }, "factory": "mxpi_tensorinfer", "next": "tee1" }, "mxpi_objectpostprocessor0": { "props": { "dataSource": "mxpi_tensorinfer0", "postProcessConfigPath": "../model/centerface.cfg", "postProcessLibPath": "../plugins/lib/plugins/libmxpi_centerfacepostprocessor.so" }, "factory": "mxpi_objectpostprocessor", "next": "mxpi_object2osdinstances0" }, "mxpi_objectpostprocessor1": { "props": { "dataSource": "mxpi_tensorinfer0", "postProcessConfigPath": "../model/centerface.cfg", "postProcessLibPath": "../plugins/lib/plugins/libmxpi_centerfacekeypointpostprocessor.so" }, "factory": "mxpi_keypointpostprocessor", "next": "mxpi_synchronize0:1" }, "mxpi_object2osdinstances0": { "props": { "colorMap": "128, 128, 255|200,200,200|0,128,255|255,128,0", "fontFace": "16", "fontScale": "0.5", "fontThickness": "1", "fontLineType": "16", "rectThickness": "1", "rectLineType": "16" }, "factory": "mxpi_object2osdinstances", "next": "mxpi_opencvosd0:1" }, "mxpi_opencvosd0": { "props": { "dataSourceImage": "mxpi_imagedecoder0", "dataSourceOsd": "mxpi_object2osdinstances0" }, "factory": "mxpi_opencvosd", "next": "mxpi_synchronize0:0" }, "mxpi_synchronize0": { "factory": "mxpi_synchronize", "next": "appsink0" }, "appsink0": { "props": { "blocksize": "4096000" }, "factory": "appsink" } } } ``` > 上述涉及的路径均使用相对路径,相对于main函数文件所在位置。 ### 5.4 后处理插件开发 后处理插件主要包含两个,一个对应人脸检测的功能,另一个对应人脸关键点。后处理插件需要对这模型的四个输出进行处理(包含热图、中心点偏移、目标框宽高和人脸五个关键点的相对目标框大小归一化后的偏移)得到各自的结果,以完成推理。 而后处理插件的开发一般根据自己的任务需求,先在api中寻找是否有已经实现好的基类,继承合适的基类可减少开发的任务量,如果没有便只能继承最基础的基类。通常包含以下几个步骤(下面以人脸检测后处理插件作为演示): #### 编写CMakeLists.txt 编写CMakeLists.txt,主要用于设置后处理动态库的目标文件以及链接相关的第三方库。每一个后处理插件都有一个CMakeLists.txt文件与之对应。编写后处理的CMakeLists.txt文件时,用户只需修改生成的后处理名和生成动态库的目标文件即可,延用原有的配置。人脸检测后处理插件的CMakeList.txt如下: ```cmake cmake_minimum_required(VERSION 3.10) project(mxpi_centerfacepostprocessor) add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0 -Dgoogle=mindxsdk_private) set(PLUGIN_NAME "mxpi_centerfacepostprocessor") set(TARGET_LIBRARY ${PLUGIN_NAME}) # 插件生成的位置 set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../lib/plugins) #在本地IDE上运行时请替换为MX_SDK_HOME的绝对路径,如set(MX_SDK_HOME /home/MindX_SDK/mxvision) set(MX_SDK_HOME $ENV{MX_SDK_HOME}) if (NOT DEFINED ENV{MX_SDK_HOME}) string(REGEX REPLACE "(.*)/(.*)/(.*)/(.*)" "\\1" MX_SDK_HOME ${CMAKE_CURRENT_SOURCE_DIR}) message(STATUS "set default MX_SDK_HOME: ${MX_SDK_HOME}") else () message(STATUS "env MX_SDK_HOME: ${MX_SDK_HOME}") endif() #包含的头文件 include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${MX_SDK_HOME}/include) include_directories(${MX_SDK_HOME}/opensource/include) include_directories(${MX_SDK_HOME}/opensource/include/gstreamer-1.0) include_directories(${MX_SDK_HOME}/opensource/include/glib-2.0) include_directories(${MX_SDK_HOME}/opensource/lib/glib-2.0/include) #链接动态库 link_directories(${MX_SDK_HOME}/lib) link_directories(${MX_SDK_HOME}/opensource/lib) add_compile_options(-std=c++11 -fPIC -fstack-protector-all -pie -Wno-deprecated-declarations) add_compile_options("-DPLUGIN_NAME=${PLUGIN_NAME}") add_definitions(-DENABLE_DVPP_INTERFACE) add_library(${TARGET_LIBRARY} SHARED MxCenterfacePostProcessor.cpp MxCenterfacePostProcessor.h) target_link_libraries(${TARGET_LIBRARY} glib-2.0 gstreamer-1.0 gobject-2.0 gstbase-1.0 gmodule-2.0 glog) target_link_libraries(${TARGET_LIBRARY} mxpidatatype plugintoolkit mxbase mindxsdk_protobuf ) #target_link_libraries(${TARGET_LIBRARY} -Wl,-z,relro,-z,now,-z,noexecstack -s) ``` #### 实现人脸框检测的cpp文件 首先,根据任务类型,选择SDK已经支持的后处理基类去派生一个新的子类,这些后处理基类分别为目标检测,分类任务,语义分割,文本生成。这些基类都继承自相同的父类——PostProcessBase。人脸检测框后处理插件继承的类为ObjectPostProcessBase; ```c++ class MxCenterfacePostProcessor : public MxBase::ObjectPostProcessBase ``` **实现基类方法:** inti函数: ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654844885252208174.png) Process函数: ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654844937949430601.png) | 输入参数 | 解释 | | ----------------- | ------------------------------------------------------------ | | tensors | 上游插件的输出,当把后处理插件编排在模型推理插件之后,这里tensors便是模型的输出。 | | objectInfos | MxBase::ObjectInfo是api内置的目标框数据结构,后处理的结果需要存放在里面。 | | resizedImageInfos | 图片size信息,包含原图的宽高和resize之后的宽高,用于后处理逻辑的计算。 | | configParamMap | 从配置文件读取得到的map,在init函数读入。 | 在Process函数中,首先调用父类的CheckAndMoveTensors()接口,对tensors的形状进行校验并搬运内存至Host侧。然后再调用后处理业务函数,这里featLayerData包含单张图片四个输出对应void*指针,数据都是以一维数组形式存储,具体的数据size、type及数据含义需要参考论文原作者的实现。在CenterFace模型中,MxCenterfacePostProcessor后处理插件逻辑包括根据置信度筛选数据、计算出人脸框、使用nms算法对人脸框去重这一系列操作,最终将结果放入objInfo中。 后处理开发完成后,增加一个对外的接口如GetObjectInstance(),以便于让业务流中后处理插件的factory能加载生成的so文件。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654845275412513003.png) > 这里对外接口根据继承的基类有不同名称,通常为Get+基类名称+Instance #### 生成插件 在Clion中点击运行按钮,即可生成对应so文件: ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654843383135724620.png) 生成插件后即可在pipeline配置文件中使用,如下: ```json "mxpi_objectpostprocessor1": { "props": { "dataSource": "mxpi_tensorinfer0", "postProcessConfigPath": "../model/centerface.cfg", "postProcessLibPath": "../plugins/lib/plugins/libmxpi_centerfacekeypointpostprocessor.so" }, "factory": "mxpi_keypointpostprocessor", "next": "XXXX"} ``` factory为后处理插件基类对应插件的名字,后处理插件实际也是用的内置的插件,开发后处理插件相当于在插件的基础上编写,仅需关注业务的具体逻辑代码,如databuff的传递等其他操作由插件完成。 如果不知道factory该填什么,可以在MX_SDK_HOME/lib/plugins下查找。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654843337671691251.png) ## 6 运行过程展示 ### 6.1 本地IDE运行 第一步:配置FaceDetectPostProcessor、KeyPointPostProcessor、C++中CMakeLists文件的SDK路径, ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654843287648131732.png) 第二步:设置cmake编译的环境变量,编译插件。 在设置>构建、执行、部署>cmake界面,找到环境,配置如下: ```bash LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64:/usr/local/Ascend/driver/lib64/; ``` ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654843212875646606.png) 加载FaceDetectPostProcessor中的CMakeLists文件,第一次加载CmakeLists文件时,选择Load Cmake Project,之后重新加载选择Reload Cmake Project。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654843151269379700.png) 加载CmakeLists文件之后,首先在①号位置选择对应的插件,这里选择的是FaceDetectPostProcessor插件,点击②编译 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654843096561305478.png) 点击之后,程序运行,运行完成会显示Finished,得到一个cmake-build-debug文件夹,并且远程会有编译生成的文件夹。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654843018575639101.png) 按以上方法将另一个插件KeyPointPostProcessor中CMakeLists文件进行编译,生成的插件都会存放在plugins目录下。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654842947888770306.png) 第三步:编译、运行main文件 接着加载main.cpp对应的CmakeLists,加载成功会自动生成Main的运行配置,准备图片test.jpg放置在C++目录下,编辑Main运行配置,添加程序实参,并配置环境变量,点击确定。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654842914614432881.png) ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654842871463441960.png) 环境变量如下,其中的MX_SDK_HOME需要替换为昇腾服务器上的绝对路径。 ```bash MX_SDK_HOME=${SDK安装路径} LD_LIBRARY_PATH=${MX_SDK_HOME}/lib:${MX_SDK_HOME}/opensource/lib:${MX_SDK_HOME}/opensource/lib64:/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64:/usr/local/Ascend/driver/lib64/ GST_PLUGIN_SCANNER=${MX_SDK_HOME}/opensource/libexec/gstreamer-1.0/gst-plugin-scanner GST_PLUGIN_PATH=${MX_SDK_HOME}/opensource/lib/gstreamer-1.0:${MX_SDK_HOME}/lib/plugins ``` 然后点击运行。 成功运行后,可在远程的C++/result文件夹中查看结果。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654842804364324769.png) ### 6.2 远程命令行运行 相对于本地运行,远程运行方式会更加简洁方便,具体参考以下操作 第一步:进入到远程文件夹 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654842773435869432.png) 第二步:输入命令: ```bash bash build.sh ``` 此时它会自动将三个CMakeLists全部编译。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654842685849257801.png) 第三步:进入C++文件夹,输入命令运行run.sh文件,假如测试图片在run.sh同级目录,名字为test.jpg,测试命令如下: ```bash cd C++ bash run.sh test.jpg #这里相对路径是相对C++/Main可执行文件的。 #或者准备图片放置在文件夹下,以下命令会依次对文件夹下的图片进行检测。 bash run.sh images ``` ![1653201293644](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654842550524626553.png) 第四步:在result文件中查看运行结果,刷新可以看到是否是刚刚运行生成的结果。 ![1653201442455](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654842482875232996.png) ## 7 常见问题 - 报错:$'\r': command not found![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654842427382418968.png) 解决方案:原因是windows和linux换行符不一致,在CLion右下角将CRLF改成LF,然后上传到远程服务器。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/10/1654842131426441396.png)
上滑加载中
推荐直播
-
华为AI技术发展与挑战:集成需求分析的实战指南
2024/11/26 周二 18:20-20:20
Alex 华为云学堂技术讲师
本期直播将综合讨论华为AI技术的发展现状,技术挑战,并深入探讨华为AI应用开发过程中的需求分析过程,从理论到实践帮助开发者快速掌握华为AI应用集成需求的框架和方法。
去报名 -
华为云DataArts+DWS助力企业数据治理一站式解决方案及应用实践
2024/11/27 周三 16:30-18:00
Walter.chi 华为云数据治理DTSE技术布道师
想知道数据治理项目中,数据主题域如何合理划分?数据标准及主数据标准如何制定?数仓分层模型如何合理规划?华为云DataArts+DWS助力企业数据治理项目一站式解决方案和应用实践告诉您答案!本期将从数据趋势、数据治理方案、数据治理规划及落地,案例分享四个方面来助力企业数据治理项目合理咨询规划及顺利实施。
去报名
热门标签