车辆检索是ReID技术的一种具体实现,跟以图搜图类似,需要使用CNN网络预提取海量车辆样本特征并进行存储(附带一些结构化属性),在检索阶段,再使用向量比对技术从海量样本中查询Top N的相似结果并返回。那么前期预提取海量车辆样本特征(以及结构化属性)该如何实现呢?VideoPipe视频分析框架能够胜任99%的视频结构化需求,覆盖了人脸识别、目标行为分析、车辆检索等等应用场景。VideoPipe完全开源(仅供学习),github地址(github.com/sherlockchou86/video_pipe_c)
下面介绍使用VideoPipe实现车辆检索的过程。
车辆检索应用主要环节
- 提取特征&结构化属性
- 海量特征存储&结构化数据存储
- 海量特征比对&关系型数据库检索
其中第2、3步骤暂不涉及,重点讲述第一步。一般提取得到的车辆图像特征都是高维数据,比如256维float型数组、甚至1204维float数组。这些高维数据一般无法被人类直观理解。在提取特征的同时,我们还可以为车辆图像提取结构化属性,比如是白车还是黑车、是小卡车还是大卡车、有天窗还是没天窗等等。我们将提取到的高维特征数据和结构化属性同时存档(存入不同类型数据库),当作待检索数据集。下面列举车辆检索第一步骤提取到的数据可能有哪些:
- 颜色:白色、黑色、蓝色、灰色、黄色、红色
- 车型:轿车、SUV、皮卡、大卡、小卡、厢式货车、大巴、依维柯
- 天窗:有、无
- 车牌:未知、具体车牌值
- 图像特征:[0.231230, -0.092778, 0.289908 …]
提取特征&结构化属性的实现
VideoPipe视频分析框架可以快速集成目标检测、图像分类、特征提取等神经网路图像算法,支持多种视频(图片)接入方式,下面代码读取指定目录下的图片,先后进行车辆检测、车型分类、特征提取等操作,最后基于车辆检测和分类的结果、以及提取得到的特征值做显示和聚合。
#include "VP.h"
#include "../nodes/vp_image_src_node.h"
#include "../nodes/vp_file_src_node.h"
#include "../nodes/infers/vp_trt_vehicle_detector.h"
#include "../nodes/infers/vp_trt_vehicle_color_classifier.h"
#include "../nodes/infers/vp_trt_vehicle_type_classifier.h"
#include "../nodes/infers/vp_trt_vehicle_feature_encoder.h"
#include "../nodes/track/vp_sort_track_node.h"
#include "../nodes/osd/vp_osd_node.h"
#include "../nodes/osd/vp_cluster_node.h"
#include "../nodes/vp_screen_des_node.h"
#include "../nodes/vp_fake_des_node.h"
#include "../utils/analysis_board/vp_analysis_board.h"
/*
* ## vehicle_cluster_based_on_classify_encoding_sample ##
* vehicle cluster based on classify(categories) and encoding(features), pipeline would display 3 windows (cluster by t-SNE, cluster by categories, detect osd result)
*/
#if vehicle_cluster_based_on_classify_encoding_sample
int main() {
VP_SET_LOG_LEVEL(vp_utils::vp_log_level::INFO);
VP_LOGGER_INIT();
// create nodes
auto image_src_0 = std::make_shared<vp_nodes::vp_image_src_node>("image_src_0", 0, "./images/vehicle/%d.jpg");
//auto file_src_0 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, "./test_video/22.mp4");
auto trt_vehicle_detector = std::make_shared<vp_nodes::vp_trt_vehicle_detector>("trt_detector", "./models/trt/vehicle/vehicle_v8.5.trt");
auto trt_vehicle_color_classifier = std::make_shared<vp_nodes::vp_trt_vehicle_color_classifier>("trt_color_cls", "./models/trt/vehicle/vehicle_color_v8.5.trt", std::vector<int>{0, 1, 2});
auto trt_vehicle_type_classifier = std::make_shared<vp_nodes::vp_trt_vehicle_type_classifier>("trt_type_cls", "./models/trt/vehicle/vehicle_type_v8.5.trt", std::vector<int>{0, 1, 2});
auto trt_vehicle_feature_encoder = std::make_shared<vp_nodes::vp_trt_vehicle_feature_encoder>("trt_encoder", "./models/trt/vehicle/vehicle_embedding_v8.5.trt", std::vector<int>{0, 1, 2});
auto osd_0 = std::make_shared<vp_nodes::vp_osd_node>("osd_0");
auto screen_des_0 = std::make_shared<vp_nodes::vp_screen_des_node>("screen_des_0", 0);
auto cluster_0 = std::make_shared<vp_nodes::vp_cluster_node>("cluster_0", true, std::vector<std::string>{"red", "white", "black", "blue", "yellow", "bus", "small_truck", "van", "tanker"}, 1000);
auto fake_des_0 = std::make_shared<vp_nodes::vp_fake_des_node>("fake_des_0", 0);
// construct pipeline
trt_vehicle_detector->attach_to({image_src_0});
//trt_vehicle_detector->attach_to({file_src_0});
trt_vehicle_color_classifier->attach_to({trt_vehicle_detector});
trt_vehicle_type_classifier->attach_to({trt_vehicle_color_classifier});
trt_vehicle_feature_encoder->attach_to({trt_vehicle_type_classifier});
// split into 2 branches automatically
/* branch of osd -> screen des*/
osd_0->attach_to({trt_vehicle_feature_encoder});
screen_des_0->attach_to({osd_0});
/* branch of cluster -> fake des*/
cluster_0->attach_to({trt_vehicle_feature_encoder});
fake_des_0->attach_to({cluster_0}); // to keep pipeline complete
// start pipeline
image_src_0->start();
//file_src_0->start();
// visualize pipeline for debug
//vp_utils::vp_analysis_board board({file_src_0});
vp_utils::vp_analysis_board board({image_src_0});
board.display();
}
#endif
上面代码运行后,可以显示4个窗口,分别是:
- Pipeline管道运行状态
- 车辆检测结果
- 车辆按分类标签(车型、颜色)显示
- 车辆按特征自动聚合(相似车辆聚合到一起)