mirror of
https://github.com/Ascend/ascend_community_projects.git
synced 2025-09-26 20:01:17 +08:00
Video-ReID
This commit is contained in:
265
Video-ReID/README.md
Normal file
265
Video-ReID/README.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# MindXSDK 视频行人重识别
|
||||
|
||||
## 1 简介
|
||||
本开发样例基于MindX SDK实现了对图片和视频流的行人重识别(Person Re-identification, ReID),支持检索给定照片、视频中的行人ID。其主要流程为:
|
||||
- 构建行人特征库:将底库图片调整大小,利用目标检测模型YOLOv3推理,检测图片中的行人,检测结果经过抠图与调整大小,再利用OSNet模型提取图片中每个行人的特征向量并保存,特征向量用于与后续的待查询图片或者视频中的行人作比较。
|
||||
- 对于查询图片或视频帧:利用目标检测模型YOLOv3推理,检测图片中的行人,检测结果经过抠图与调整大小,再利用OSNet模型提取图片中每个行人的特征向量。
|
||||
- 行人检索:将查询图片中行人的特征向量与底库中的特征向量做比较,为每个查询图片中的行人检索最有可能的ID,通过识别框和文字信息进行可视化标记。
|
||||
- 如果输入是图片,最终得到标记过的图片文件,如果是视频流,得到标记过的H264格式视频文件
|
||||
|
||||
## 2 目录结构
|
||||
本工程名称为Video-ReID,工程目录如下图所示:
|
||||
```
|
||||
video-ReID
|
||||
|---- config
|
||||
| | |---- coco.names
|
||||
| | |---- yolov3_tf_bs1_fp16.cfg
|
||||
|---- data
|
||||
| |---- gallery // 行人底库图片文件夹
|
||||
| |---- query
|
||||
| |---- images // 查询场景图片文件夹
|
||||
| |---- videos // 查询场景视频文件夹,也可根据推流时实际环境配置存放位置
|
||||
|---- models // 目标检测、OSNet模型与配置文件夹
|
||||
| |---- OSNet
|
||||
| | | |---- aipp.config
|
||||
|---- YOLOv3
|
||||
| | | |---- tf_aipp.config
|
||||
|---- pipeline // 流水线配置文件夹
|
||||
| | |---- image.pipeline
|
||||
| | |---- gallery.pipeline
|
||||
| | |---- video.pipeline
|
||||
|---- plugins // 自定义插件目录
|
||||
| |---- PluginFeatureMatch
|
||||
|---- output // 结果保存文件夹
|
||||
| |---- gallery
|
||||
| |---- query
|
||||
| |---- images
|
||||
| |---- videos //需自行创建
|
||||
|---- image.py
|
||||
|---- gallery.py
|
||||
|---- video.py
|
||||
|---- run.sh
|
||||
|---- README.md
|
||||
```
|
||||
> 由于无法在Gitee上创建空文件夹,请按照该工程目录,自行创建output文件夹、data文件夹与其内部的文件夹
|
||||
|
||||
## 3 依赖
|
||||
| 软件名称 | 版本 |
|
||||
| :--------: | :------: |
|
||||
|ubuntu 18.04|18.04.1 LTS |
|
||||
|CANN|5.0.4|
|
||||
|MindX SDK|2.0.4|
|
||||
|Python| 3.9.2|
|
||||
|numpy | 1.21.0 |
|
||||
|opencv_python|4.5.2|
|
||||
|
||||
- 设置环境变量(请确认install_path路径是否正确)
|
||||
```
|
||||
#执行如下命令
|
||||
. ${SDK-path}/set_env.sh
|
||||
. ${ascend_toolkit_path}/set_env.sh
|
||||
```
|
||||
|
||||
请注意MindX SDK使用python版本为3.9.2,如出现无法找到python对应lib库请在root下安装python3.9开发库
|
||||
```
|
||||
apt-get install libpython3.9
|
||||
```
|
||||
|
||||
- 推理中涉及到第三方软件依赖如下表所示。
|
||||
|
||||
| 依赖软件 | 版本 | 说明 | 使用教程 |
|
||||
| -------- | ---------- | -------------------------------- | ------------------------------------------------------------ |
|
||||
| live555 | 1.10 | 实现视频转 rstp 进行推流 | [链接](https://gitee.com/ascend/mindxsdk-referenceapps/blob/master/docs/参考资料/Live555离线视频转RTSP说明文档.md) |
|
||||
| ffmpeg | 2022-06-27 | 实现 mp4 格式视频转为264格式视频 | [链接](https://gitee.com/ascend/mindxsdk-referenceapps/blob/master/docs/参考资料/pc端ffmpeg安装教程.md) |
|
||||
|
||||
## 4 模型转换
|
||||
行人重识别先采用了yolov3模型将图片中的行人检测出来,然后利用OsNet模型获取行人的特征向量。由于yolov3模型和OsNet模型分别是基于Pytorch和Tensorflow的深度模型,我们需要借助ATC工具分别将其转换成对应的.om模型。
|
||||
|
||||
### 4.1 yolov3的模型转换:
|
||||
|
||||
**步骤1** 获取yolov3的原始模型(.pb文件)和相应的配置文件(.cfg文件)
|
||||
      [原始模型下载链接](https://www.hiascend.com/zh/software/modelzoo/models/detail/1/ba2a4c054a094ef595da288ecbc7d7b4)
|
||||
|
||||
**步骤2** 将获取到的yolov3模型.pb文件和.cfg文件存放至:“项目所在目录/models/YOLOv3/”
|
||||
|
||||
**步骤3** .om模型转换
|
||||
进入“项目所在目录/models/YOLOv3”
|
||||
|
||||
- 使用ATC将.pb文件转成为.om文件
|
||||
```
|
||||
atc --model=yolov3_tf.pb --framework=3 --output=yolov3 --output_type=FP32 --soc_version=Ascend310 --input_shape="input:1,416,416,3" --out_nodes="yolov3/yolov3_head/Conv_6/BiasAdd:0;yolov3/yolov3_head/Conv_14/BiasAdd:0;yolov3/yolov3_head/Conv_22/BiasAdd:0" --log=info --insert_op_conf=tf_aipp.cfg
|
||||
```
|
||||
- 执行完模型转换脚本后,若提示如下信息说明模型转换成功,可以在该路径下找到名为yolov3.om模型文件。
|
||||
(可以通过修改output参数来重命名这个.om文件)
|
||||
```
|
||||
ATC run success, welcome to the next use.
|
||||
```
|
||||
|
||||
### 4.2 OSNet的模型转换
|
||||
|
||||
#### 4.2.1 模型概述
|
||||
      [OSNet论文地址](https://arxiv.org/pdf/1905.00953.pdf)
|
||||
      [OSNet代码地址](https://github.com/KaiyangZhou/deep-person-reid)
|
||||
|
||||
#### 4.2.2 模型转换步骤
|
||||
|
||||
**步骤1** 从ModelZoo源码包中获取OSNet的onnx模型文件(osnet_x1_0.onnx)
|
||||
      [权重文件源码包下载链接](https://www.hiascend.com/zh/software/modelzoo/models/detail/1/43a754e306c6461d86dafced5046121f)
|
||||
|
||||
**步骤2** 将获取到的onnx模型存放至:“项目所在目录/models/OSNet/”
|
||||
|
||||
**步骤3** .om模型转换
|
||||
进入“项目所在目录/models/OSNet”
|
||||
|
||||
- 使用ATC将.onnx文件转成为.om文件
|
||||
```
|
||||
atc --framework=5 --model=./osnet_x1_0.onnx --input_format=NCHW --insert_op_conf=./aipp.config --input_shape="image:-1,3,256,128" --dynamic_batch_size="1,2,3,4,5,6,7,8" --output=osnet --log=debug --soc_version=Ascend310
|
||||
// dynamic参数为支持的动态batchsize,可根据实际图片中可能出现的行人数目更改
|
||||
```
|
||||
- 执行完模型转换脚本后,若提示如下信息说明模型转换成功,可以在该路径下找到名为yolov3.om模型文件。
|
||||
(可以通过修改output参数来重命名这个.om文件)
|
||||
```
|
||||
ATC run success, welcome to the next use.
|
||||
```
|
||||
经过上述操作,可以在“项目所在目录/models”的子目录下找到yolov3.om模型和osnet.om模型,模型转换操作已全部完成
|
||||
|
||||
### 4.3 参考链接
|
||||
> 模型转换使用了ATC工具,如需更多信息请参考:[ATC工具使用指南-快速入门](https://support.huaweicloud.com/tg-cannApplicationDev330/atlasatc_16_0005.html)
|
||||
> Yolov3模型转换的参考链接:[ATC YOLOv3(FP16)](https://www.hiascend.com/zh/software/modelzoo/models/detail/1/ba2a4c054a094ef595da288ecbc7d7b4)
|
||||
> OSNet模型转换的参考链接:[OSNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/OSNet)
|
||||
|
||||
## 5 准备
|
||||
|
||||
### 5.1 数据
|
||||
|
||||
为适配网络输入以及性能要求,建议输入图片或视频流长宽比接近1:1,图像长宽均需为偶数,待检测行人范围像素面积大于5120且宽度大于32像素,长度大于16像素,且图像后缀为jpg/JPG。
|
||||
涉及文件夹
|
||||
> “项目所在目录/data/gallery”:用于存放制作行人底库的场景图片
|
||||
建议针对待检测的行人单人正面,侧面,背面各采集图片作为其底库。图片中行人清晰醒目且身体完整。
|
||||
|
||||
> “项目所在目录/data/query/images”:用于存放待查询行人图片
|
||||
可检测行人正面,侧面,背面。要求图片中行人清晰醒目且身体尽量完整。
|
||||
|
||||
> “项目所在目录/data/query/videos”:用于存放待查询行人视频
|
||||
可检测行人正面,侧面,背面。要求视频帧中行人清晰醒目且身体尽量完整。
|
||||
|
||||
### 5.2 编译插件
|
||||
|
||||
项目需要用到自定义插件进行特征匹配与重标定,自定义插件源码目录为“项目所在目录/plugins/PluginFeatureMatch”
|
||||
|
||||
#### 5.2.1 编译插件
|
||||
```
|
||||
> bash build.sh
|
||||
```
|
||||
编译后会在${MX_SDK_HOME}/lib/plugins/目录下生成libmxpi_featurematch.so文件
|
||||
|
||||
#### 5.2.2 为编译获得的.so文件授予640权限.
|
||||
|
||||
编译参考[插件编译指南](https://support.huawei.com/enterprise/zh/doc/EDOC1100234263/21d24289)
|
||||
|
||||
### 5.3 视频推流
|
||||
按照第 3 小结软件依赖安装 live555 和 ffmpeg,按照 Live555离线视频转RTSP说明文档 将 mp4 视频转换为 h264 格式。并将生成的 264 格式的视频上传到 live/mediaServer 目录下,然后修改 项目所在目录/pipeline 目录下的 video.pipeline 文件中 mxpi_rtspsrc0 的内容。
|
||||
```
|
||||
"mxpi_rtspsrc0": {
|
||||
"props": {
|
||||
"rtspUrl":"rtsp://xxx.xxx.xxx.xxx:xxxx/xxx.264", // 修改为自己开发板的地址和文件名
|
||||
"channelId": "0",
|
||||
"timeout": "30"
|
||||
},
|
||||
"factory": "mxpi_rtspsrc",
|
||||
"next": "mxpi_videodecoder0"
|
||||
},
|
||||
```
|
||||
|
||||
### 5.4 适用场景
|
||||
|
||||
项目适用于大部分行人目标较完整且醒目可见的场景,对于行人不完整程度高,或者行人底库中缺少同一行人对应机位的参照时,检测框或行人重标定可能会出现误差,请根据实际应用进行数据选择和处理。
|
||||
对于视频,每帧的处理时长约为200ms,建议拉流视频帧率在5左右,若出现内存不足等情况请适当降低帧率。
|
||||
|
||||
## 6 测试
|
||||
|
||||
### 6.1 获取om模型
|
||||
```
|
||||
步骤详见4: 模型转换
|
||||
```
|
||||
### 6.2 准备
|
||||
```
|
||||
步骤详见5: 准备
|
||||
```
|
||||
### 6.3 配置pipeline
|
||||
根据所需场景,配置pipeline文件,调整路径参数等。
|
||||
```
|
||||
# 配置mxpi_tensorinfer插件的yolov3.om模型加载路径(三个pipeline均需配置)
|
||||
"mxpi_tensorinfer0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_imageresize0",
|
||||
"modelPath": "models/YOLOv3/yolov3.om(这里根据你的命名或路径进行更改)"
|
||||
},
|
||||
"factory": "mxpi_tensorinfer",
|
||||
"next": "mxpi_objectpostprocessor0"
|
||||
},
|
||||
# 配置mxpi_objectpostprocessor插件的yolov3.cfg配置文件加载路径以及SDN的安装路径(三个pipeline均需配置)
|
||||
"mxpi_objectpostprocessor0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_tensorinfer0",
|
||||
"postProcessConfigPath": "config/yolov3_tf_bs1_fp16.cfg(这里根据你的命名或路径进行更改)",
|
||||
"labelPath": "config/coco.names",
|
||||
"postProcessLibPath": "libyolov3postprocess.so"
|
||||
},
|
||||
"factory": "mxpi_objectpostprocessor",
|
||||
"next": "mxpi_objectselector0"
|
||||
},
|
||||
# 配置mxpi_tensorinfer插件的OsNet.om模型加载路径(三个pipeline均需配置)
|
||||
"mxpi_tensorinfer1": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_imagecrop0",
|
||||
"dynamicStrategy": "Upper",
|
||||
"modelPath": "models/OSNet/osnet.om",
|
||||
"waitingTime": "1"
|
||||
},
|
||||
"factory": "mxpi_tensorinfer",
|
||||
"next": "mxpi_featurematch0"
|
||||
},
|
||||
|
||||
```
|
||||
### 6.4 执行
|
||||
|
||||
#### 6.4.1 构建行人特征库
|
||||
```
|
||||
bash run.sh gallery
|
||||
```
|
||||
执行成功后会打印单张图片处理耗时并在output/gallery目录下生成.txt标签文件和.bin特征向量存储文件。
|
||||
|
||||
#### 6.4.2 图片查询
|
||||
```
|
||||
bash run.sh image
|
||||
```
|
||||
执行成功后会打印单张图片处理耗时并在output/query/images目录下生成标记了Reid目标的图片输出。
|
||||
经测试,端到端处理耗时在200ms以内。
|
||||
|
||||
#### 6.4.3 视频查询
|
||||
```
|
||||
bash run.sh video 60 # 60s为处理视频流时长参数,可根据实际情况修改
|
||||
```
|
||||
执行成功后会在output/query/videos目录下获得标记了Reid目标的h264格式视频文件。
|
||||
|
||||
### 6.5 查看结果
|
||||
执行命令后,可在“项目所在目录/output”路径下查看结果。
|
||||
|
||||
|
||||
## 7 参考链接
|
||||
> 特定行人检索:[Person Search Demo](https://github.com/KaiyangZhou/deep-person-reid)
|
||||
|
||||
|
||||
## 8 Q&A
|
||||
### 8.1 在运行查询脚本时出现"[DVPP: image width out of range] The crop width of image No.[0] is out of range [32,4096]"
|
||||
> 这里的错误是因为yolov3模型检测到的目标过小,调大“mxpi_objectselector0”插件的MinArea参数或者更新“项目所在目录/config/yolov3_tf_bs1_fp16.cfg”文件,将OBJECTNESS_THRESH适度调大可解决该问题
|
||||
|
||||
### 8.2 运行video.py时出现"[6003][stream change state fail] create stream(queryVideoProcess) failed."
|
||||
> 可能是因为video.pipeline中filelink插件的保存路径文件夹未创建,请手动创建(output/query/videos).
|
||||
|
||||
### 8.3 运行脚本时出现 streamInstance GetResult return nullptr.
|
||||
> 可能是因为图像/视频里没有检测到行人,请更换有显著行人的图像输入。
|
||||
|
||||
### 8.4 视频处理时出现 "[Error code unknown] Failed to send frame.","[DVPP: decode H264 or H265 fail] Decode video failed.",且在销毁stream时出现 “Failed to destroy vdec channel.", "Failed to destroy stream:queryVideoProcess"或出现 "Malloc device memory failed."
|
||||
> 此错误可能是因为视频帧率过高,请适当降低.264视频帧率。
|
81
Video-ReID/config/coco.names
Normal file
81
Video-ReID/config/coco.names
Normal file
@@ -0,0 +1,81 @@
|
||||
# This file is originally from https://github.com/pjreddie/darknet/blob/master/data/coco.names
|
||||
person
|
||||
bicycle
|
||||
car
|
||||
motorbike
|
||||
aeroplane
|
||||
bus
|
||||
train
|
||||
truck
|
||||
boat
|
||||
traffic light
|
||||
fire hydrant
|
||||
stop sign
|
||||
parking meter
|
||||
bench
|
||||
bird
|
||||
cat
|
||||
dog
|
||||
horse
|
||||
sheep
|
||||
cow
|
||||
elephant
|
||||
bear
|
||||
zebra
|
||||
giraffe
|
||||
backpack
|
||||
umbrella
|
||||
handbag
|
||||
tie
|
||||
suitcase
|
||||
frisbee
|
||||
skis
|
||||
snowboard
|
||||
sports ball
|
||||
kite
|
||||
baseball bat
|
||||
baseball glove
|
||||
skateboard
|
||||
surfboard
|
||||
tennis racket
|
||||
bottle
|
||||
wine glass
|
||||
cup
|
||||
fork
|
||||
knife
|
||||
spoon
|
||||
bowl
|
||||
banana
|
||||
apple
|
||||
sandwich
|
||||
orange
|
||||
broccoli
|
||||
carrot
|
||||
hot dog
|
||||
pizza
|
||||
donut
|
||||
cake
|
||||
chair
|
||||
sofa
|
||||
pottedplant
|
||||
bed
|
||||
diningtable
|
||||
toilet
|
||||
tvmonitor
|
||||
laptop
|
||||
mouse
|
||||
remote
|
||||
keyboard
|
||||
cell phone
|
||||
microwave
|
||||
oven
|
||||
toaster
|
||||
sink
|
||||
refrigerator
|
||||
book
|
||||
clock
|
||||
vase
|
||||
scissors
|
||||
teddy bear
|
||||
hair drier
|
||||
toothbrush
|
10
Video-ReID/config/yolov3_tf_bs1_fp16.cfg
Normal file
10
Video-ReID/config/yolov3_tf_bs1_fp16.cfg
Normal file
@@ -0,0 +1,10 @@
|
||||
CLASS_NUM=80
|
||||
BIASES_NUM=18
|
||||
BIASES=10,13,16,30,33,23,30,61,62,45,59,119,116,90,156,198,373,326
|
||||
SCORE_THRESH=0.3
|
||||
OBJECTNESS_THRESH=0.3
|
||||
IOU_THRESH=0.45
|
||||
YOLO_TYPE=3
|
||||
ANCHOR_DIM=3
|
||||
MODEL_TYPE=0
|
||||
RESIZE_FLAG=0
|
145
Video-ReID/get_gallery_features.py
Normal file
145
Video-ReID/get_gallery_features.py
Normal file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
"""
|
||||
Copyright(C) Huawei Technologies Co.,Ltd. 2012-2021 All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import time
|
||||
import numpy as np
|
||||
import MxpiDataType_pb2 as MxpiDataType
|
||||
from StreamManagerApi import StreamManagerApi, MxDataInput, StringVector
|
||||
|
||||
|
||||
GALLERY_STREAM_NAME = b'galleryProcess'
|
||||
IN_PLUGIN_ID = 0
|
||||
OUT_PLUGIN_ID = 0
|
||||
|
||||
|
||||
def initialize_stream():
|
||||
"""
|
||||
Initialize stream galleryImageProcess for detecting and re-identifying persons in galley images
|
||||
|
||||
:arg:
|
||||
None
|
||||
|
||||
:return:
|
||||
Stream api
|
||||
"""
|
||||
|
||||
stream_pi = StreamManagerApi()
|
||||
ret = stream_pi.InitManager()
|
||||
if ret != 0:
|
||||
error_message = "Failed to init Stream manager, ret=%s" % str(ret)
|
||||
print(error_message)
|
||||
exit()
|
||||
|
||||
# creating stream based on json strings in the pipeline file: 'ReID.pipeline'
|
||||
with open("pipeline/gallery.pipeline", 'rb') as f:
|
||||
pipeline = f.read()
|
||||
|
||||
ret = stream_pi.CreateMultipleStreams(pipeline)
|
||||
if ret != 0:
|
||||
error_message = "Failed to create Stream, ret=%s" % str(ret)
|
||||
print(error_message)
|
||||
exit()
|
||||
|
||||
return stream_pi
|
||||
|
||||
|
||||
def get_gallery_feature(input_dir, output_dir, stream_api):
|
||||
"""
|
||||
Extract the features of gallery images, save the feature vector and the Pids to files
|
||||
|
||||
:arg:
|
||||
imgPath: the directory of gallery images
|
||||
outputDir: the directory of gallery output files
|
||||
streamApi: stream api
|
||||
|
||||
:return:
|
||||
None
|
||||
"""
|
||||
|
||||
# constructing the results returned by the queryImageProcess stream
|
||||
key_vec = StringVector()
|
||||
key_vec.push_back(b"mxpi_tensorinfer1")
|
||||
|
||||
# check the query file
|
||||
if os.path.exists(input_dir) != 1:
|
||||
error_message = 'The img dir does not exist.'
|
||||
print(error_message)
|
||||
exit()
|
||||
if len(os.listdir(input_dir)) == 0:
|
||||
error_message = 'The img file is empty.'
|
||||
print(error_message)
|
||||
exit()
|
||||
if os.path.exists(output_dir) != 1:
|
||||
root = os.getcwd()
|
||||
os.makedirs(os.path.join(root, output_dir))
|
||||
features = []
|
||||
pids = []
|
||||
|
||||
# extract the features for all images in gallery file
|
||||
for root, dirs, files in os.walk(input_dir):
|
||||
for file in files:
|
||||
if file.endswith('.jpg') or file.endswith('.JPG'):
|
||||
data_input = MxDataInput()
|
||||
file_path = os.path.join(root, file)
|
||||
with open(file_path, 'rb') as f:
|
||||
data_input.data = f.read()
|
||||
start = time.time()
|
||||
# send the prepared data to the stream
|
||||
unique_id = stream_api.SendData(GALLERY_STREAM_NAME, IN_PLUGIN_ID, data_input)
|
||||
if unique_id < 0:
|
||||
error_message = 'Failed to send data to queryImageProcess stream.'
|
||||
print(error_message)
|
||||
exit()
|
||||
# get infer result
|
||||
infer_result = stream_api.GetProtobuf(GALLERY_STREAM_NAME, OUT_PLUGIN_ID, key_vec)
|
||||
end = time.time()
|
||||
print("time:", end-start)
|
||||
# checking whether the infer results is valid or not
|
||||
if infer_result.size() == 0:
|
||||
error_message = 'Unable to get effective infer results, please check the stream log for details'
|
||||
print(error_message)
|
||||
exit()
|
||||
|
||||
tensor_packages = MxpiDataType.MxpiTensorPackageList()
|
||||
tensor_packages.ParseFromString(infer_result[0].messageBuf)
|
||||
feature = np.frombuffer(tensor_packages.tensorPackageVec[0].tensorVec[0].dataStr,
|
||||
dtype=np.float32)
|
||||
features.append(feature)
|
||||
pids.append(file.split('.')[0])
|
||||
else:
|
||||
print('Input image only support jpg')
|
||||
exit()
|
||||
|
||||
features = np.array(features)
|
||||
features.tofile(os.path.join(output_dir, 'gallery_features.bin'))
|
||||
pids = np.array(pids).T
|
||||
np.savetxt(os.path.join(output_dir, 'persons.txt'), pids, fmt='%s')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--galleryInputDir', type=str, default='data/gallery', help="Gallery File Path")
|
||||
parser.add_argument('--galleryOutputDir', type=str, default='output/gallery', help="Gallery Features Output Path")
|
||||
opt = parser.parse_args()
|
||||
stream_manager_api = initialize_stream()
|
||||
get_gallery_feature(opt.galleryInputDir, opt.galleryOutputDir, stream_manager_api)
|
||||
|
||||
stream_manager_api.DestroyAllStreams()
|
131
Video-ReID/image.py
Normal file
131
Video-ReID/image.py
Normal file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
"""
|
||||
Copyright(C) Huawei Technologies Co.,Ltd. 2012-2021 All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import stat
|
||||
import os
|
||||
import time
|
||||
from StreamManagerApi import StreamManagerApi, MxDataInput
|
||||
|
||||
|
||||
QUERY_STREAM_NAME = b'queryImageProcess'
|
||||
|
||||
IN_PLUGIN_ID = 0
|
||||
OUT_PLUGIN_ID = 0
|
||||
|
||||
|
||||
def initialize_stream():
|
||||
"""
|
||||
Initialize stream queryImageProcess for detecting and re-identifying persons in image
|
||||
|
||||
:arg:
|
||||
None
|
||||
|
||||
:return:
|
||||
Stream api
|
||||
"""
|
||||
|
||||
stream_pi = StreamManagerApi()
|
||||
ret = stream_pi.InitManager()
|
||||
if ret != 0:
|
||||
error_message = "Failed to init Stream manager, ret=%s" % str(ret)
|
||||
print(error_message)
|
||||
exit()
|
||||
|
||||
# creating stream based on json strings in the pipeline file: 'ReID.pipeline'
|
||||
with open("pipeline/image.pipeline", 'rb') as f:
|
||||
pipeline = f.read()
|
||||
|
||||
ret = stream_pi.CreateMultipleStreams(pipeline)
|
||||
if ret != 0:
|
||||
error_message = "Failed to create Stream, ret=%s" % str(ret)
|
||||
print(error_message)
|
||||
exit()
|
||||
|
||||
return stream_pi
|
||||
|
||||
|
||||
def reid(input_dir, output_dir, stream_api):
|
||||
|
||||
"""
|
||||
detecting and re-identifying persons in videos
|
||||
|
||||
:arg:
|
||||
inputDir: the directory of query images
|
||||
outputDir: the directory of output images
|
||||
streamApi: stream api
|
||||
|
||||
:return:
|
||||
None
|
||||
"""
|
||||
|
||||
if os.path.exists(input_dir) != 1:
|
||||
error_message = 'The img dir does not exist.'
|
||||
print(error_message)
|
||||
exit()
|
||||
if len(os.listdir(input_dir)) == 0:
|
||||
error_message = 'The img file is empty.'
|
||||
print(error_message)
|
||||
exit()
|
||||
if os.path.exists(output_dir) != 1:
|
||||
root = os.getcwd()
|
||||
os.makedirs(os.path.join(root, output_dir))
|
||||
|
||||
for root, dirs, files in os.walk(input_dir):
|
||||
for file in files:
|
||||
if file.endswith('.jpg') or file.endswith('.JPG'):
|
||||
data_input = MxDataInput()
|
||||
file_path = os.path.join(root, file)
|
||||
with open(file_path, 'rb') as f:
|
||||
data_input.data = f.read()
|
||||
start = time.time()
|
||||
|
||||
unique_id = stream_api.SendData(QUERY_STREAM_NAME, IN_PLUGIN_ID, data_input)
|
||||
if unique_id < 0:
|
||||
error_message = 'Failed to send data to queryImageProcess stream.'
|
||||
print(error_message)
|
||||
exit()
|
||||
|
||||
# get infer result
|
||||
infer_result = stream_api.GetResult(QUERY_STREAM_NAME, OUT_PLUGIN_ID)
|
||||
if infer_result.errorCode:
|
||||
error_message = 'Unable to get effective infer results, please check the stream log for details'
|
||||
print(error_message)
|
||||
exit()
|
||||
end = time.time()
|
||||
out_path = os.path.join(output_dir, file)
|
||||
flags = os.O_WRONLY | os.O_CREAT # Sets how files are read and written
|
||||
modes = stat.S_IWUSR | stat.S_IRUSR # Set file permissions
|
||||
with os.fdopen(os.open(out_path, flags, modes), 'wb') as f:
|
||||
f.write(infer_result.data)
|
||||
print("time:", end - start)
|
||||
else:
|
||||
print('Input image only support jpg')
|
||||
exit()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--queryInputDir', type=str, default='data/query/images', help="Query Images Input Dir")
|
||||
parser.add_argument('--queryOutputDir', type=str, default='output/query/images', help="Query Images Output Dir")
|
||||
opt = parser.parse_args()
|
||||
stream_manager_api = initialize_stream()
|
||||
reid(opt.queryInputDir, opt.queryOutputDir, stream_manager_api)
|
||||
|
||||
stream_manager_api.DestroyAllStreams()
|
21
Video-ReID/models/OSNet/aipp.config
Normal file
21
Video-ReID/models/OSNet/aipp.config
Normal file
@@ -0,0 +1,21 @@
|
||||
aipp_op {
|
||||
aipp_mode: static
|
||||
input_format : YUV420SP_U8
|
||||
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
|
||||
|
||||
src_image_size_w: 128
|
||||
src_image_size_h: 256
|
||||
}
|
22
Video-ReID/models/YOLOv3/tf_aipp.cfg
Normal file
22
Video-ReID/models/YOLOv3/tf_aipp.cfg
Normal file
@@ -0,0 +1,22 @@
|
||||
aipp_op {
|
||||
aipp_mode: static
|
||||
input_format : YUV420SP_U8
|
||||
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
|
||||
var_reci_chn_0 : 0.003921568627451
|
||||
var_reci_chn_1 : 0.003921568627451
|
||||
var_reci_chn_2 : 0.003921568627451
|
||||
}
|
||||
|
109
Video-ReID/pipeline/gallery.pipeline
Normal file
109
Video-ReID/pipeline/gallery.pipeline
Normal file
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"galleryProcess": {
|
||||
"stream_config": {
|
||||
"deviceId": "0"
|
||||
},
|
||||
"appsrc0": {
|
||||
"props": {
|
||||
"blocksize": "409600"
|
||||
},
|
||||
"factory": "appsrc",
|
||||
"next": "mxpi_imagedecoder0"
|
||||
},
|
||||
"mxpi_imagedecoder0": {
|
||||
"factory": "mxpi_imagedecoder",
|
||||
"next": "mxpi_imageresize0"
|
||||
},
|
||||
"mxpi_imageresize0": {
|
||||
"props": {
|
||||
"resizeHeight": "416",
|
||||
"resizeWidth": "416"
|
||||
},
|
||||
"factory": "mxpi_imageresize",
|
||||
"next": "mxpi_tensorinfer0"
|
||||
},
|
||||
"mxpi_tensorinfer0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_imageresize0",
|
||||
"modelPath": "models/YOLOv3/yolov3.om",
|
||||
"waitingTime": "1"
|
||||
},
|
||||
"factory": "mxpi_tensorinfer",
|
||||
"next": "mxpi_objectpostprocessor0"
|
||||
},
|
||||
"mxpi_objectpostprocessor0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_tensorinfer0",
|
||||
"postProcessConfigPath": "config/yolov3_tf_bs1_fp16.cfg",
|
||||
"labelPath": "config/coco.names",
|
||||
"postProcessLibPath": "libyolov3postprocess.so"
|
||||
},
|
||||
"factory": "mxpi_objectpostprocessor",
|
||||
"next": "mxpi_objectselector0"
|
||||
},
|
||||
"mxpi_objectselector0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_objectpostprocessor0",
|
||||
"FirstDetectionFilter": {
|
||||
"Type": "Area",
|
||||
"TopN": 1,
|
||||
"BottomN": 0,
|
||||
"MinArea": 0,
|
||||
"MaxArea": 0,
|
||||
"ConfThresh": 0.1
|
||||
}
|
||||
},
|
||||
"factory": "mxpi_objectselector",
|
||||
"next": "mxpi_distributor0"
|
||||
},
|
||||
"mxpi_distributor0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_objectselector0",
|
||||
"classIds": "0"
|
||||
},
|
||||
"factory": "mxpi_distributor",
|
||||
"next": "queue2"
|
||||
},
|
||||
"queue2": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_imagecrop0"
|
||||
},
|
||||
"mxpi_imagecrop0":{
|
||||
"props":{
|
||||
"dataSource": "mxpi_distributor0_0",
|
||||
"dataSourceImage": "mxpi_imageresize0",
|
||||
"resizeHeight":"256",
|
||||
"resizeWidth":"128"
|
||||
},
|
||||
"factory":"mxpi_imagecrop",
|
||||
"next":"mxpi_imageresize1"
|
||||
},
|
||||
"mxpi_imageresize1": {
|
||||
"props": {
|
||||
"resizeHeight": "256",
|
||||
"resizeWidth": "128"
|
||||
},
|
||||
"factory": "mxpi_imageresize",
|
||||
"next": "mxpi_tensorinfer1"
|
||||
},
|
||||
"mxpi_tensorinfer1": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_imageresize1",
|
||||
"dynamicStrategy": "Upper",
|
||||
"modelPath": "models/OSNet/osnet.om",
|
||||
"waitingTime": "1"
|
||||
},
|
||||
"factory": "mxpi_tensorinfer",
|
||||
"next": "appsink0"
|
||||
},
|
||||
"appsink0": {
|
||||
"props": {
|
||||
"blocksize": "4096000"
|
||||
},
|
||||
"factory": "appsink"
|
||||
}
|
||||
}
|
||||
}
|
185
Video-ReID/pipeline/image.pipeline
Normal file
185
Video-ReID/pipeline/image.pipeline
Normal file
@@ -0,0 +1,185 @@
|
||||
{
|
||||
"queryImageProcess": {
|
||||
"stream_config": {
|
||||
"deviceId": "0"
|
||||
},
|
||||
"appsrc0": {
|
||||
"props": {
|
||||
"blocksize": "409600"
|
||||
},
|
||||
"factory": "appsrc",
|
||||
"next": "mxpi_imagedecoder0"
|
||||
},
|
||||
"mxpi_imagedecoder0": {
|
||||
"factory": "mxpi_imagedecoder",
|
||||
"next": "tee0"
|
||||
},
|
||||
"tee0": {
|
||||
"factory": "tee",
|
||||
"next": [
|
||||
"queue0",
|
||||
"queue1"
|
||||
]
|
||||
},
|
||||
"queue0": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_imageresize0"
|
||||
},
|
||||
"mxpi_imageresize0": {
|
||||
"props": {
|
||||
"resizeHeight": "416",
|
||||
"resizeWidth": "416"
|
||||
},
|
||||
"factory": "mxpi_imageresize",
|
||||
"next": "mxpi_tensorinfer0"
|
||||
},
|
||||
"mxpi_tensorinfer0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_imageresize0",
|
||||
"modelPath": "models/YOLOv3/yolov3.om",
|
||||
"waitingTime": "1"
|
||||
},
|
||||
"factory": "mxpi_tensorinfer",
|
||||
"next": "mxpi_objectpostprocessor0"
|
||||
},
|
||||
"queue1": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_opencvosd0:0"
|
||||
},
|
||||
"mxpi_objectpostprocessor0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_tensorinfer0",
|
||||
"postProcessConfigPath": "config/yolov3_tf_bs1_fp16.cfg",
|
||||
"labelPath": "config/coco.names",
|
||||
"postProcessLibPath": "libyolov3postprocess.so"
|
||||
},
|
||||
"factory": "mxpi_objectpostprocessor",
|
||||
"next": "mxpi_objectselector0"
|
||||
},
|
||||
"mxpi_objectselector0": {
|
||||
"props": {
|
||||
"FirstDetectionFilter": {
|
||||
"Type": "Area",
|
||||
"TopN": 0,
|
||||
"BottomN": 0,
|
||||
"MinArea": 5120,
|
||||
"MaxArea": 173056,
|
||||
"ConfThresh": 0.4
|
||||
}
|
||||
},
|
||||
"factory": "mxpi_objectselector",
|
||||
"next": "mxpi_distributor0"
|
||||
},
|
||||
"mxpi_distributor0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_objectselector0",
|
||||
"classIds": "0"
|
||||
},
|
||||
"factory": "mxpi_distributor",
|
||||
"next": "tee1"
|
||||
},
|
||||
"tee1": {
|
||||
"factory": "tee",
|
||||
"next": [
|
||||
"queue2",
|
||||
"queue3"
|
||||
]
|
||||
},
|
||||
"queue2": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_imagecrop0"
|
||||
},
|
||||
"queue3": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_featurematch0:1"
|
||||
},
|
||||
"mxpi_imagecrop0":{
|
||||
"props":{
|
||||
"dataSource": "mxpi_distributor0_0",
|
||||
"dataSourceImage": "mxpi_imageresize0",
|
||||
"resizeHeight":"256",
|
||||
"resizeWidth":"128"
|
||||
},
|
||||
"factory":"mxpi_imagecrop",
|
||||
"next":"mxpi_tensorinfer1"
|
||||
},
|
||||
"mxpi_tensorinfer1": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_imagecrop0",
|
||||
"dynamicStrategy": "Upper",
|
||||
"modelPath": "models/OSNet/osnet.om",
|
||||
"waitingTime": "1"
|
||||
},
|
||||
"factory": "mxpi_tensorinfer",
|
||||
"next": "mxpi_featurematch0"
|
||||
},
|
||||
"mxpi_featurematch0": {
|
||||
"props": {
|
||||
"status": "1",
|
||||
"querySource": "mxpi_tensorinfer1",
|
||||
"objectSource": "mxpi_distributor0_0",
|
||||
"galleryFeaturesPath": "output/gallery/gallery_features.bin",
|
||||
"galleryIdsPath": "output/gallery/persons.txt",
|
||||
"metric": "euclidean",
|
||||
"threshold": "-1"
|
||||
},
|
||||
"factory": "mxpi_featurematch",
|
||||
"next": "mxpi_object2osdinstances0"
|
||||
},
|
||||
"mxpi_object2osdinstances0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_featurematch0",
|
||||
"colorMap":"255,100,100|100,255,100",
|
||||
"fontFace": "1",
|
||||
"fontScale": "0.8",
|
||||
"fontThickness": "1",
|
||||
"fontLineType": "8",
|
||||
"rectThickness": "1",
|
||||
"rectLineType": "8"
|
||||
},
|
||||
"factory": "mxpi_object2osdinstances",
|
||||
"next": "queue4"
|
||||
},
|
||||
"queue4": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_opencvosd0:1"
|
||||
},
|
||||
"mxpi_opencvosd0":{
|
||||
"factory":"mxpi_opencvosd",
|
||||
"next":"mxpi_imageencoder0"
|
||||
},
|
||||
|
||||
"mxpi_imageencoder0":{
|
||||
"factory":"mxpi_imageencoder",
|
||||
"next":"queue5"
|
||||
},
|
||||
"queue5": {
|
||||
"props": {
|
||||
"max-size-buffers": "100"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next":"appsink0"
|
||||
},
|
||||
"appsink0": {
|
||||
"props": {
|
||||
"blocksize": "4096000"
|
||||
},
|
||||
"factory": "appsink"
|
||||
}
|
||||
}
|
||||
}
|
215
Video-ReID/pipeline/video.pipeline
Normal file
215
Video-ReID/pipeline/video.pipeline
Normal file
@@ -0,0 +1,215 @@
|
||||
{
|
||||
"queryVideoProcess": {
|
||||
"stream_config": {
|
||||
"deviceId": "0"
|
||||
},
|
||||
"mxpi_rtspsrc0": {
|
||||
"factory": "mxpi_rtspsrc",
|
||||
"props": {
|
||||
"rtspUrl":"rtsp://xxx.xxx.xxx.xxx:xxxx/xxx.264",
|
||||
"channelId": "0",
|
||||
"timeout": "30"
|
||||
},
|
||||
"next": "mxpi_videodecoder0"
|
||||
},
|
||||
"mxpi_videodecoder0": {
|
||||
"factory": "mxpi_videodecoder",
|
||||
"props": {
|
||||
"inputVideoFormat": "H264",
|
||||
"outputImageFormat": "YUV420SP_NV12"
|
||||
},
|
||||
"next": "tee0"
|
||||
},
|
||||
"tee0": {
|
||||
"factory": "tee",
|
||||
"next": [
|
||||
"queue0",
|
||||
"queue1"
|
||||
]
|
||||
},
|
||||
"queue0": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_imageresize0"
|
||||
},
|
||||
"mxpi_imageresize0": {
|
||||
"props": {
|
||||
"resizeHeight": "416",
|
||||
"resizeWidth": "416"
|
||||
},
|
||||
"factory": "mxpi_imageresize",
|
||||
"next": "mxpi_tensorinfer0"
|
||||
},
|
||||
"queue1": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_opencvosd0:0"
|
||||
},
|
||||
"mxpi_tensorinfer0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_imageresize0",
|
||||
"modelPath": "models/YOLOv3/yolov3.om",
|
||||
"waitingTime": "50"
|
||||
},
|
||||
"factory": "mxpi_tensorinfer",
|
||||
"next": "mxpi_objectpostprocessor0"
|
||||
},
|
||||
"mxpi_objectpostprocessor0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_tensorinfer0",
|
||||
"postProcessConfigPath": "config/yolov3_tf_bs1_fp16.cfg",
|
||||
"labelPath": "config/coco.names",
|
||||
"postProcessLibPath": "libyolov3postprocess.so"
|
||||
},
|
||||
"factory": "mxpi_objectpostprocessor",
|
||||
"next": "mxpi_objectselector0"
|
||||
},
|
||||
"mxpi_objectselector0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_objectpostprocessor0",
|
||||
"FirstDetectionFilter": {
|
||||
"Type": "Area",
|
||||
"TopN": 0,
|
||||
"BottomN": 0,
|
||||
"MinArea": 5120,
|
||||
"MaxArea": 173056,
|
||||
"ConfThresh": 0.3
|
||||
}
|
||||
},
|
||||
"factory": "mxpi_objectselector",
|
||||
"next": "mxpi_distributor0"
|
||||
},
|
||||
"mxpi_distributor0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_objectselector0",
|
||||
"classIds": "0"
|
||||
},
|
||||
"factory": "mxpi_distributor",
|
||||
"next": "tee1"
|
||||
},
|
||||
"tee1": {
|
||||
"factory": "tee",
|
||||
"next": [
|
||||
"queue2",
|
||||
"queue3"
|
||||
]
|
||||
},
|
||||
"queue2": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_imagecrop0"
|
||||
},
|
||||
"queue3": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_featurematch0:1"
|
||||
},
|
||||
"mxpi_imagecrop0":{
|
||||
"props":{
|
||||
"dataSource": "mxpi_distributor0_0",
|
||||
"dataSourceImage": "mxpi_imageresize0",
|
||||
"resizeHeight":"256",
|
||||
"resizeWidth":"128"
|
||||
},
|
||||
"factory":"mxpi_imagecrop",
|
||||
"next":"mxpi_imageresize1"
|
||||
},
|
||||
"mxpi_imageresize1": {
|
||||
"props": {
|
||||
"resizeHeight": "256",
|
||||
"resizeWidth": "128"
|
||||
},
|
||||
"factory": "mxpi_imageresize",
|
||||
"next": "mxpi_tensorinfer1"
|
||||
},
|
||||
"mxpi_tensorinfer1": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_imageresize1",
|
||||
"dynamicStrategy": "Upper",
|
||||
"modelPath": "models/OSNet/osnet.om",
|
||||
"waitingTime": "60"
|
||||
},
|
||||
"factory": "mxpi_tensorinfer",
|
||||
"next": "mxpi_featurematch0"
|
||||
},
|
||||
"mxpi_featurematch0": {
|
||||
"props": {
|
||||
"status": "1",
|
||||
"querySource": "mxpi_tensorinfer1",
|
||||
"objectSource": "mxpi_distributor0_0",
|
||||
"galleryFeaturesPath": "output/gallery/gallery_features.bin",
|
||||
"galleryIdsPath": "output/gallery/persons.txt",
|
||||
"metric": "euclidean",
|
||||
"threshold": "-1"
|
||||
},
|
||||
"factory": "mxpi_featurematch",
|
||||
"next": "mxpi_object2osdinstances0"
|
||||
},
|
||||
"mxpi_object2osdinstances0": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_featurematch0",
|
||||
"colorMap":"255,100,100|100,255,100",
|
||||
"fontFace": "1",
|
||||
"fontScale": "0.8",
|
||||
"fontThickness": "1",
|
||||
"fontLineType": "8",
|
||||
"rectThickness": "1",
|
||||
"rectLineType": "8"
|
||||
},
|
||||
"factory": "mxpi_object2osdinstances",
|
||||
"next": "queue4"
|
||||
},
|
||||
"queue4": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_opencvosd0:1"
|
||||
},
|
||||
"mxpi_opencvosd0":{
|
||||
"factory":"mxpi_opencvosd",
|
||||
"next":"queue6"
|
||||
},
|
||||
"queue6": {
|
||||
"props": {
|
||||
"max-size-buffers": "200"
|
||||
},
|
||||
"factory": "queue",
|
||||
"next": "mxpi_imageresize2"
|
||||
},
|
||||
"mxpi_imageresize2": {
|
||||
"props": {
|
||||
"dataSource": "mxpi_opencvosd0",
|
||||
"resizeHeight": "416",
|
||||
"resizeWidth": "416"
|
||||
},
|
||||
"factory": "mxpi_imageresize",
|
||||
"next": "mxpi_videoencoder0"
|
||||
},
|
||||
"mxpi_videoencoder0":{
|
||||
"props": {
|
||||
"imageHeight": "416",
|
||||
"imageWidth": "416",
|
||||
"iFrameInterval": "200",
|
||||
"fps": "1"
|
||||
},
|
||||
"factory":"mxpi_videoencoder",
|
||||
"next":"filesink0"
|
||||
},
|
||||
"filesink0":{
|
||||
"props":{
|
||||
"blocksize":"40960000",
|
||||
"location":"output/query/videos/reid.264"
|
||||
},
|
||||
"factory":"filesink"
|
||||
}
|
||||
}
|
||||
}
|
46
Video-ReID/plugins/PluginFeatureMatch/CMakeLists.txt
Normal file
46
Video-ReID/plugins/PluginFeatureMatch/CMakeLists.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(mxpi_featurematch)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
set(PLUGIN_NAME "mxpi_featurematch")
|
||||
set(TARGET_LIBRARY ${PLUGIN_NAME})
|
||||
|
||||
add_compile_options(-fPIC -fstack-protector-all -g -Wl,-z,relro,-z,now,-z -pie -Wall)
|
||||
add_compile_options(-std=c++11 -Wno-deprecated-declarations)
|
||||
add_compile_options("-DPLUGIN_NAME=${PLUGIN_NAME}")
|
||||
|
||||
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0 -Dgoogle=mindxsdk_private)
|
||||
add_definitions(-DENABLE_DVPP_INTERFACE)
|
||||
|
||||
|
||||
set(MX_SDK_HOME "$ENV{MX_SDK_HOME}")
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${MX_SDK_HOME}/lib/plugins/)
|
||||
|
||||
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/opencv4)
|
||||
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)
|
||||
|
||||
file(GLOB PLUGIN_SRC ./*.cpp)
|
||||
message(${PLUGIN_SRC})
|
||||
|
||||
add_library(${TARGET_LIBRARY} SHARED ${PLUGIN_SRC})
|
||||
target_link_libraries(${TARGET_LIBRARY}
|
||||
mxpidatatype
|
||||
plugintoolkit
|
||||
mxbase
|
||||
streammanager
|
||||
mindxsdk_protobuf
|
||||
glib-2.0
|
||||
gstreamer-1.0
|
||||
gobject-2.0
|
||||
gstbase-1.0
|
||||
gmodule-2.0
|
||||
)
|
335
Video-ReID/plugins/PluginFeatureMatch/Plugin_FeatureMatch.cpp
Normal file
335
Video-ReID/plugins/PluginFeatureMatch/Plugin_FeatureMatch.cpp
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright(C) 2021. Huawei Technologies Co.,Ltd. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MxBase/Log/Log.h"
|
||||
#include "MxBase/Tensor/TensorBase/TensorBase.h"
|
||||
#include "Plugin_FeatureMatch.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
using namespace MxPlugins;
|
||||
using namespace MxTools;
|
||||
using namespace MxBase;
|
||||
using namespace cv;
|
||||
|
||||
|
||||
APP_ERROR PluginFeatureMatch::Init(std::map<std::string, std::shared_ptr<void>> &configParamMap) {
|
||||
LogInfo << "Begin to initialize PluginFeatureMatch(" << pluginName_ << ").";
|
||||
// Get the property values by key
|
||||
std::shared_ptr<std::string> querySource = std::static_pointer_cast<std::string>(configParamMap["querySource"]);
|
||||
querySource_ = *querySource;
|
||||
std::shared_ptr<std::string> objectSource = std::static_pointer_cast<std::string>(configParamMap["objectSource"]);
|
||||
objectSource_ = *objectSource;
|
||||
std::shared_ptr<std::string> galleryFeaturesPath = std::static_pointer_cast<std::string>(configParamMap["galleryFeaturesPath"]);
|
||||
galleryFeaturesPath_ = *galleryFeaturesPath;
|
||||
std::shared_ptr<std::string> galleryIdsPath = std::static_pointer_cast<std::string>(configParamMap["galleryIdsPath"]);
|
||||
galleryIdsPath_ = *galleryIdsPath;
|
||||
std::shared_ptr<std::string> metric = std::static_pointer_cast<std::string>(configParamMap["metric"]);
|
||||
metric_ = *metric;
|
||||
|
||||
std::shared_ptr<std::float_t> threshold = std::static_pointer_cast<float_t>(configParamMap["threshold"]);
|
||||
threshold_ = *threshold;
|
||||
|
||||
ReadGalleryFeatures(galleryFeaturesPath_, galleryIdsPath_, galleryFeatures, galleryIds);
|
||||
LogInfo << "End to initialize PluginFeatureMatch(" << pluginName_ << ").";
|
||||
return APP_ERR_OK;
|
||||
}
|
||||
|
||||
APP_ERROR PluginFeatureMatch::DeInit() {
|
||||
LogInfo << "Begin to deinitialize PluginFeatureMatch(" << pluginName_ << ").";
|
||||
LogInfo << "End to deinitialize PluginFeatureMatch(" << pluginName_ << ").";
|
||||
return APP_ERR_OK;
|
||||
}
|
||||
|
||||
APP_ERROR PluginFeatureMatch::CheckDataSource(MxTools::MxpiMetadataManager &mxpiMetadataManager,
|
||||
MxTools::MxpiMetadataManager &mxpiMetadataManager1) {
|
||||
if (mxpiMetadataManager.GetMetadata(querySource_) == nullptr) {
|
||||
LogDebug << GetError(APP_ERR_METADATA_IS_NULL, pluginName_)
|
||||
<< "class metadata is null. please check"
|
||||
<< "Your property querySource(" << querySource_ << ").";
|
||||
return APP_ERR_METADATA_IS_NULL;
|
||||
}
|
||||
if (mxpiMetadataManager1.GetMetadata(objectSource_) == nullptr) {
|
||||
LogDebug << GetError(APP_ERR_METADATA_IS_NULL, pluginName_)
|
||||
<< "class metadata is null. please check"
|
||||
<< "Your property objectSource(" << objectSource_ << ").";
|
||||
return APP_ERR_METADATA_IS_NULL;
|
||||
}
|
||||
return APP_ERR_OK;
|
||||
}
|
||||
|
||||
void EuclideanSquaredDistance(Mat queryFeatures, Mat galleryFeatures, Mat &distMat) {
|
||||
int admm_beta = 1;
|
||||
int admm_alpha = -2;
|
||||
int square = 2;
|
||||
Mat qdst1;
|
||||
pow(queryFeatures, square, qdst1);
|
||||
Mat qdst2;
|
||||
reduce(qdst1, qdst2, 1, REDUCE_SUM);
|
||||
|
||||
Mat qdst3 = Mat(qdst2.rows, galleryFeatures.rows, CV_32FC1);
|
||||
for (int i = 0; i < galleryFeatures.rows; i++) {
|
||||
Mat dstTemp = qdst3.col(i);
|
||||
qdst2.copyTo(dstTemp);
|
||||
}
|
||||
|
||||
Mat gdst1;
|
||||
pow(galleryFeatures, square, gdst1);
|
||||
Mat gdst2;
|
||||
reduce(gdst1, gdst2, 1, REDUCE_SUM);
|
||||
|
||||
Mat gdst3 = Mat(gdst2.rows, queryFeatures.rows, CV_32FC1);
|
||||
for (int i = 0; i < queryFeatures.rows;i++) {
|
||||
Mat dstTemp = gdst3.col(i);
|
||||
gdst2.copyTo(dstTemp);
|
||||
}
|
||||
|
||||
Mat gdst4;
|
||||
transpose(gdst3, gdst4);
|
||||
Mat dst1 = qdst3 +gdst4;
|
||||
|
||||
Mat gdst5;
|
||||
transpose(galleryFeatures, gdst5);
|
||||
Mat dst2 = queryFeatures * gdst5;
|
||||
|
||||
distMat = admm_beta * dst1 + admm_alpha * dst2;
|
||||
}
|
||||
|
||||
void CosineDistance(Mat queryFeatures, Mat galleryFeatures, Mat &distMat) {
|
||||
Mat gdst1;
|
||||
|
||||
transpose(galleryFeatures, gdst1);
|
||||
distMat = queryFeatures * gdst1;
|
||||
}
|
||||
|
||||
APP_ERROR PluginFeatureMatch::ComputeDistance(MxpiTensorPackageList queryTensors,
|
||||
Mat galleryFeatures, int tensorSize, Mat &distMat) {
|
||||
Mat queryFeatures = Mat::zeros(tensorSize, queryTensors.
|
||||
tensorpackagevec(0).tensorvec(0).tensorshape(1), CV_32FC1);
|
||||
|
||||
for (int i = 0; i < tensorSize; i++) {
|
||||
Mat dstTemp = queryFeatures.row(i);
|
||||
auto vec = queryTensors.tensorpackagevec(i).tensorvec(0);
|
||||
Mat feature = Mat(vec.tensorshape(0), vec.tensorshape(1), CV_32FC1,
|
||||
(void *) vec.tensordataptr());
|
||||
feature.copyTo(dstTemp);
|
||||
}
|
||||
if (!(metric_.compare("euclidean"))) {
|
||||
EuclideanSquaredDistance(queryFeatures, galleryFeatures, distMat);
|
||||
}
|
||||
else if (!(metric_.compare("cosine"))) {
|
||||
CosineDistance(queryFeatures, galleryFeatures, distMat);
|
||||
}
|
||||
return APP_ERR_OK;
|
||||
}
|
||||
|
||||
void PluginFeatureMatch::GenerateOutput(MxpiObjectList srcObjectList, Mat distMat,
|
||||
int tensorSize, std::vector<std::string> galleryIds,
|
||||
MxpiObjectList &dstMxpiObjectList) {
|
||||
std::vector<float> minValues = {};
|
||||
for (int i = 0; i < tensorSize; i++) {
|
||||
auto minValue = std::min_element(distMat.ptr<float>(i, 0), distMat.ptr<float>(i, 0+distMat.cols));
|
||||
if (threshold_ == -1 || *minValue < threshold_) {
|
||||
int minIndex = std::distance(distMat.ptr<float>(i, 0), minValue);
|
||||
auto objvec = srcObjectList.objectvec(i);
|
||||
MxpiObject* dstMxpiObject = dstMxpiObjectList.add_objectvec();
|
||||
MxpiMetaHeader* dstMxpiMetaHeaderList = dstMxpiObject->add_headervec();
|
||||
dstMxpiMetaHeaderList->set_datasource(objectSource_);
|
||||
dstMxpiMetaHeaderList->set_memberid(0);
|
||||
|
||||
dstMxpiObject->set_x0(objvec.x0());
|
||||
dstMxpiObject->set_y0(objvec.y0());
|
||||
dstMxpiObject->set_x1(objvec.x1());
|
||||
dstMxpiObject->set_y1(objvec.y1());
|
||||
|
||||
// Generate ClassList
|
||||
MxpiClass* dstMxpiClass = dstMxpiObject->add_classvec();
|
||||
MxpiMetaHeader* dstMxpiMetaHeaderList_c = dstMxpiClass->add_headervec();
|
||||
dstMxpiMetaHeaderList_c->set_datasource(objectSource_);
|
||||
dstMxpiMetaHeaderList_c->set_memberid(0);
|
||||
dstMxpiClass->set_classid(i);
|
||||
dstMxpiClass->set_confidence(objvec.classvec(0).confidence());
|
||||
dstMxpiClass->set_classname(galleryIds[minIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PluginFeatureMatch::ReadGalleryFeatures(std::string featuresPath,
|
||||
std::string idsPath, Mat &galleryFeatures,
|
||||
std::vector<std::string> &galleryIds) {
|
||||
// 读取gallery的人名
|
||||
std::ifstream ifile(idsPath);
|
||||
std::string str1;
|
||||
while (std::getline(ifile, str1)) {
|
||||
galleryIds.push_back(str1);
|
||||
}
|
||||
ifile.close();
|
||||
|
||||
// 读取gallery特征库
|
||||
int featureLen = 512;
|
||||
const char* feaPath = featuresPath.c_str();
|
||||
FILE* fp = fopen(feaPath, "rb");
|
||||
galleryFeatures = Mat::zeros(int(galleryIds.size()), featureLen, CV_32FC1);
|
||||
for (int i = 0; i < int(galleryIds.size()); i++)
|
||||
{
|
||||
for (int j = 0; j < featureLen; j++)
|
||||
{
|
||||
fread(&galleryFeatures.at<float>(i, j), 1, sizeof(float), fp);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
|
||||
APP_ERROR PluginFeatureMatch::Process(std::vector<MxpiBuffer *> &mxpiBuffer) {
|
||||
LogInfo << "Begin to process PluginFeatureMatch.";
|
||||
// Get MxpiClassList from MxpiBuffer
|
||||
MxpiBuffer *inputMxpiBuffer = mxpiBuffer[0];
|
||||
MxpiMetadataManager mxpiMetadataManager(*inputMxpiBuffer);
|
||||
auto errorInfoPtr = mxpiMetadataManager.GetErrorInfo();
|
||||
MxpiBuffer *inputMxpiBuffer1 = mxpiBuffer[1];
|
||||
MxpiMetadataManager mxpiMetadataManager1(*inputMxpiBuffer1);
|
||||
auto errorInfoPtr1 = mxpiMetadataManager1.GetErrorInfo();
|
||||
MxpiErrorInfo mxpiErrorInfo;
|
||||
if (errorInfoPtr != nullptr | errorInfoPtr1 != nullptr) {
|
||||
ErrorInfo_ << GetError(APP_ERR_COMM_FAILURE, pluginName_)
|
||||
<< "PluginFeatureMatch process is not implemented";
|
||||
mxpiErrorInfo.ret = APP_ERR_COMM_FAILURE;
|
||||
mxpiErrorInfo.errorInfo = ErrorInfo_.str();
|
||||
LogError << "PluginFeatureMatch process is not implemented";
|
||||
return APP_ERR_COMM_FAILURE;
|
||||
}
|
||||
|
||||
// check data source
|
||||
APP_ERROR ret = CheckDataSource(mxpiMetadataManager, mxpiMetadataManager1);
|
||||
if (ret != APP_ERR_OK) {
|
||||
SendData(0, *inputMxpiBuffer1);
|
||||
return ret;
|
||||
}
|
||||
std::shared_ptr<void> queryListMetadata = mxpiMetadataManager.GetMetadata(querySource_);
|
||||
std::shared_ptr<void> objectListMetadata = mxpiMetadataManager1.GetMetadata(objectSource_);
|
||||
if (queryListMetadata == nullptr || objectListMetadata == nullptr) {
|
||||
ErrorInfo_ << GetError(APP_ERR_METADATA_IS_NULL, pluginName_) << "Metadata is NULL, failed";
|
||||
mxpiErrorInfo.ret = APP_ERR_METADATA_IS_NULL;
|
||||
mxpiErrorInfo.errorInfo = ErrorInfo_.str();
|
||||
return APP_ERR_METADATA_IS_NULL;
|
||||
}
|
||||
std::shared_ptr<MxpiTensorPackageList> srcQueryListPtr = std::static_pointer_cast<MxpiTensorPackageList>(queryListMetadata);
|
||||
std::shared_ptr<MxpiObjectList> srcObjectListPtr = std::static_pointer_cast<MxpiObjectList>(objectListMetadata);
|
||||
std::shared_ptr<MxpiObjectList> resultObjectListPtr = std::make_shared<MxpiObjectList>();
|
||||
int objectSize = (*srcObjectListPtr).objectvec_size();
|
||||
int tensorSize = (*srcQueryListPtr).tensorpackagevec_size();
|
||||
|
||||
Mat distMat = Mat(tensorSize, int(galleryIds.size()), CV_32FC1);
|
||||
if (objectSize > 0 && objectSize == tensorSize) {
|
||||
ret = ComputeDistance(*srcQueryListPtr, galleryFeatures, tensorSize, distMat);
|
||||
}
|
||||
|
||||
GenerateOutput(*srcObjectListPtr, distMat, tensorSize, galleryIds, *resultObjectListPtr);
|
||||
ret = mxpiMetadataManager1.AddProtoMetadata(pluginName_, std::static_pointer_cast<void>(resultObjectListPtr));
|
||||
if (ret != APP_ERR_OK) {
|
||||
LogError << ErrorInfo_.str();
|
||||
SendMxpiErrorInfo(*inputMxpiBuffer1, pluginName_, ret, ErrorInfo_.str());
|
||||
SendData(0, *inputMxpiBuffer1);
|
||||
}
|
||||
// Send the data to downstream plugin
|
||||
SendData(0, *inputMxpiBuffer1);
|
||||
|
||||
LogInfo << "End to process PluginFeatureMatch(" << elementName_ << ").";
|
||||
return APP_ERR_OK;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<void>> PluginFeatureMatch::DefineProperties() {
|
||||
std::vector<std::shared_ptr<void>> properties;
|
||||
// Get the action category from previous plugin
|
||||
auto querySource = std::make_shared<ElementProperty<std::string>>(ElementProperty<std::string> {
|
||||
STRING,
|
||||
"querySource",
|
||||
"queryFeatureSource",
|
||||
"query infer output ",
|
||||
"default", "NULL", "NULL"
|
||||
});
|
||||
|
||||
auto objectSource = std::make_shared<ElementProperty<std::string>>(ElementProperty<std::string> {
|
||||
STRING,
|
||||
"objectSource",
|
||||
"queryobjectSource",
|
||||
"detection infer postprocess output ",
|
||||
"default", "NULL", "NULL"
|
||||
});
|
||||
|
||||
// The action of interest file path
|
||||
auto galleryFeaturesPath = std::make_shared<ElementProperty<std::string>>(ElementProperty<std::string> {
|
||||
STRING,
|
||||
"galleryFeaturesPath",
|
||||
"features of gallery file path",
|
||||
"the path of gallery images features file",
|
||||
"NULL", "NULL", "NULL"
|
||||
});
|
||||
|
||||
auto galleryIdsPath = std::make_shared<ElementProperty<std::string>>(ElementProperty<std::string> {
|
||||
STRING,
|
||||
"galleryIdsPath",
|
||||
"id of gallery file path",
|
||||
"the path of gallery person name file",
|
||||
"NULL", "NULL", "NULL"
|
||||
});
|
||||
|
||||
auto metric = std::make_shared<ElementProperty<std::string>>(ElementProperty<std::string> {
|
||||
STRING,
|
||||
"metric",
|
||||
"metric",
|
||||
"the method of compute distance, select from 'euclidean', 'cosine'.",
|
||||
"euclidean", "NULL", "NULL"
|
||||
});
|
||||
|
||||
auto threshold = std::make_shared<ElementProperty<float>>(ElementProperty<float> {
|
||||
FLOAT,
|
||||
"threshold",
|
||||
"distanceThreshold",
|
||||
"if distance is more than threshold,not matched gallery",
|
||||
-1.0, -1.0, 1000.0
|
||||
});
|
||||
|
||||
properties.push_back(querySource);
|
||||
properties.push_back(objectSource);
|
||||
properties.push_back(galleryFeaturesPath);
|
||||
properties.push_back(galleryIdsPath);
|
||||
properties.push_back(metric);
|
||||
properties.push_back(threshold);
|
||||
return properties;
|
||||
}
|
||||
|
||||
MxpiPortInfo PluginFeatureMatch::DefineInputPorts() {
|
||||
MxpiPortInfo inputPortInfo;
|
||||
std::vector<std::vector<std::string>> value = {{"ANY"}, {"ANY"}};
|
||||
GenerateStaticInputPortsInfo(value, inputPortInfo);
|
||||
return inputPortInfo;
|
||||
}
|
||||
|
||||
MxpiPortInfo PluginFeatureMatch::DefineOutputPorts() {
|
||||
MxpiPortInfo outputPortInfo;
|
||||
// Output: {{MxpiObjectList}}
|
||||
std::vector<std::vector<std::string>> value = {{"ANY"}};
|
||||
GenerateStaticOutputPortsInfo(value, outputPortInfo);
|
||||
return outputPortInfo;
|
||||
}
|
||||
|
||||
namespace {
|
||||
MX_PLUGIN_GENERATE(PluginFeatureMatch)
|
||||
}
|
111
Video-ReID/plugins/PluginFeatureMatch/Plugin_FeatureMatch.h
Normal file
111
Video-ReID/plugins/PluginFeatureMatch/Plugin_FeatureMatch.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright(C) 2021. Huawei Technologies Co.,Ltd. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SDKMEMORY_PLUGINFEATUREMATCH_H
|
||||
#define SDKMEMORY_PLUGINFEATUREMATCH_H
|
||||
|
||||
#include "opencv2/opencv.hpp"
|
||||
#include "opencv2/core/mat.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "MxBase/ErrorCode/ErrorCode.h"
|
||||
#include "MxTools/PluginToolkit/base/MxPluginGenerator.h"
|
||||
#include "MxTools/PluginToolkit/base/MxPluginBase.h"
|
||||
#include "MxTools/PluginToolkit/metadata/MxpiMetadataManager.h"
|
||||
#include "MxTools/Proto/MxpiDataType.pb.h"
|
||||
#include "MxBase/ErrorCode/ErrorCode.h"
|
||||
|
||||
|
||||
/**
|
||||
* This plug is to recognize whether the object's action is a Violent Action and alarm.
|
||||
*/
|
||||
|
||||
namespace MxPlugins {
|
||||
class PluginFeatureMatch : public MxTools::MxPluginBase {
|
||||
public:
|
||||
/**
|
||||
* @description: Init configs.
|
||||
* @param configParamMap: config.
|
||||
* @return: Error code.
|
||||
*/
|
||||
APP_ERROR Init(std::map<std::string, std::shared_ptr<void>> &configParamMap) override;
|
||||
|
||||
/**
|
||||
* @description: DeInit device.
|
||||
* @return: Error code.
|
||||
*/
|
||||
APP_ERROR DeInit() override;
|
||||
|
||||
/**
|
||||
* @description: Plugin_FeatureMatch plugin process.
|
||||
* @param mxpiBuffer: data receive from the previous.
|
||||
* @return: Error code.
|
||||
*/
|
||||
APP_ERROR Process(std::vector<MxTools::MxpiBuffer *> &mxpiBuffer) override;
|
||||
|
||||
/**
|
||||
* @description: Plugin_FeatureMatch plugin define properties.
|
||||
* @return: properties.
|
||||
*/
|
||||
static std::vector<std::shared_ptr<void>> DefineProperties();
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @brief Define the number and data type of input ports.
|
||||
* @return MxTools::MxpiPortInfo.
|
||||
*/
|
||||
static MxTools::MxpiPortInfo DefineInputPorts();
|
||||
|
||||
/**
|
||||
* @api
|
||||
* @brief Define the number and data type of output ports.
|
||||
* @return MxTools::MxpiPortInfo.
|
||||
*/
|
||||
static MxTools::MxpiPortInfo DefineOutputPorts();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @api
|
||||
* @brief Check metadata.
|
||||
* @param MxTools::MxpiMetadataManager.
|
||||
* @return Error Code.
|
||||
*/
|
||||
APP_ERROR CheckDataSource(MxTools::MxpiMetadataManager &mxpiMetadataManager,
|
||||
MxTools::MxpiMetadataManager &mxpiMetadataManager1);
|
||||
|
||||
APP_ERROR ComputeDistance(MxTools::MxpiTensorPackageList queryTensors,
|
||||
cv::Mat galleryFeatures, int tensorSize, cv::Mat &distMat);
|
||||
|
||||
void GenerateOutput(MxTools::MxpiObjectList srcObjectList, cv::Mat distMat,
|
||||
int tensorSize, std::vector<std::string> galleryIds,
|
||||
MxTools::MxpiObjectList &dstMxpiObjectList);
|
||||
|
||||
void ReadGalleryFeatures(std::string featuresPath,
|
||||
std::string idsPath, cv::Mat &galleryFeatures, std::vector<std::string> &galleryIds);
|
||||
|
||||
std::string querySource_ = ""; // previous plugin MxpiClassList
|
||||
std::string objectSource_ = "";
|
||||
std::string galleryFeaturesPath_ = "";
|
||||
std::string galleryIdsPath_ = "";
|
||||
std::string metric_ = "";
|
||||
std::ostringstream ErrorInfo_; // Error Code
|
||||
float threshold_ = 0.0;
|
||||
cv::Mat galleryFeatures = cv::Mat();
|
||||
std::vector<std::string> galleryIds = {};
|
||||
};
|
||||
}
|
||||
#endif
|
36
Video-ReID/plugins/PluginFeatureMatch/build.sh
Normal file
36
Video-ReID/plugins/PluginFeatureMatch/build.sh
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2021 Huawei Technologies Co., Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.mitations under the License.
|
||||
|
||||
set -e
|
||||
|
||||
current_folder="$( cd "$(dirname "$0")" ;pwd -P )"
|
||||
|
||||
function build_plugin() {
|
||||
build_path=$current_folder/build
|
||||
if [ -d "$build_path" ]; then
|
||||
rm -rf "$build_path"
|
||||
else
|
||||
echo "file $build_path is not exist."
|
||||
fi
|
||||
mkdir -p "$build_path"
|
||||
cd "$build_path"
|
||||
cmake ..
|
||||
make -j
|
||||
cd ..
|
||||
exit 0
|
||||
}
|
||||
|
||||
build_plugin
|
||||
exit 0
|
30
Video-ReID/run.sh
Normal file
30
Video-ReID/run.sh
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
# Copyright(C) 2021. Huawei Technologies Co.,Ltd. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
MODE=$1
|
||||
DURATION=$2
|
||||
|
||||
|
||||
if [ ${MODE} = "image" ]; then
|
||||
python image.py
|
||||
elif [ ${MODE} = "video" ]; then
|
||||
python video.py --duration ${DURATION}
|
||||
elif [ ${MODE} = "gallery" ]; then
|
||||
python get_gallery_features.py
|
||||
else
|
||||
echo -e "The mode must be image or video or gallery"
|
||||
fi
|
||||
|
||||
exit 0
|
83
Video-ReID/video.py
Normal file
83
Video-ReID/video.py
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
"""
|
||||
Copyright(C) Huawei Technologies Co.,Ltd. 2012-2021 All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import time
|
||||
from StreamManagerApi import StreamManagerApi
|
||||
|
||||
|
||||
def initialize_stream():
|
||||
"""
|
||||
Initialize stream for detecting and re-identifying persons in video
|
||||
|
||||
:arg:
|
||||
None
|
||||
|
||||
:return:
|
||||
Stream api
|
||||
"""
|
||||
stream_api = StreamManagerApi()
|
||||
ret = stream_api.InitManager()
|
||||
if ret != 0:
|
||||
error_message = "Failed to init Stream manager, ret=%s" % str(ret)
|
||||
print(error_message)
|
||||
exit()
|
||||
|
||||
# creating stream based on json strings in the pipeline file: 'ReID.pipeline'
|
||||
with open("pipeline/video.pipeline", 'rb') as f:
|
||||
pipeline = f.read()
|
||||
|
||||
ret = stream_api.CreateMultipleStreams(pipeline)
|
||||
if ret != 0:
|
||||
error_message = "Failed to create Stream, ret=%s" % str(ret)
|
||||
print(error_message)
|
||||
exit()
|
||||
|
||||
return stream_api
|
||||
|
||||
|
||||
def wait(duration):
|
||||
|
||||
"""
|
||||
Wait for destroy streams
|
||||
|
||||
:arg:
|
||||
duration: Duration of process video
|
||||
|
||||
:return:
|
||||
None
|
||||
"""
|
||||
|
||||
start = time.time()
|
||||
|
||||
while True:
|
||||
now = time.time()
|
||||
cost_time = now - start
|
||||
if cost_time >= duration:
|
||||
break
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--duration', type=float, default= 30, help="Duration Of Process Video")
|
||||
opt = parser.parse_args()
|
||||
stream_manager_api = initialize_stream()
|
||||
wait(opt.duration)
|
||||
|
||||
stream_manager_api.DestroyAllStreams()
|
Reference in New Issue
Block a user