first commit

This commit is contained in:
陈赣
2026-06-03 12:43:14 +08:00
commit ba76cfae28
608 changed files with 120791 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
#include <opencv2/core/core.hpp>
#include <string>
#include <vector>
#include <map>
#include "../models/vehicle_plate_detector.h"
#include "../models/vehicle_detector.h"
using namespace std;
/*
* vehicle detect demo
*/
std::map<std::string, cv::Scalar> colors {{"car", cv::Scalar(255, 0, 0)},
{"bus", cv::Scalar(0, 255, 255)},
{"truck", cv::Scalar(0, 255, 0)}};
int main() {
std::string vehicle_model_path = "./vp_data/models/trt/vehicle/vehicle_v8.5.trt";
auto image = cv::imread("./vp_data/test_images/vehicle/0.jpg");
auto image2 = cv::imread("./vp_data/test_images/vehicle/1.jpg");
auto vehicle_detector = new trt_vehicle::VehicleDetector(vehicle_model_path);
std::vector<cv::Mat> img_datas = {image, image2};
std::vector<std::vector<trt_vehicle::ObjBox>> results;
vehicle_detector->detect(img_datas, results);
for (int i = 0; i < results.size(); i++)
{
/* code */
for (int j = 0; j < results[i].size(); j++)
{
/* code */
auto& objbox = results[i][j];
cv::rectangle(img_datas[i], cv::Rect(objbox.x, objbox.y, objbox.width, objbox.height), colors.at(objbox.label), 2);
cv::putText(img_datas[i], objbox.label + std::to_string(objbox.score), cv::Point(objbox.x, objbox.y), 1, 0.8, colors.at(objbox.label));
}
}
cv::imshow("image", image);
cv::imshow("image2", image2);
cv::waitKey(0);
delete vehicle_detector;
}

View File

@@ -0,0 +1,143 @@
#include <opencv2/core/core.hpp>
#include <opencv2/freetype.hpp>
#include <string>
#include <vector>
#include <memory>
#include <experimental/filesystem>
#include "../models/vehicle_feature_encoder.h"
#include "../../../utils/vp_utils.h"
#include "../../bhtsne/tsne.h" // t-SNE algo
using namespace std;
/*
* vehicle cluster demo, reduce dims of features and display them on 2D screen.
*/
// extract feature for vehicle
void extract_feature(std::string vehicle_img_path, std::vector<float>& feature) {
static std::string feature_model_path = "./vp_data/models/trt/vehicle/vehicle_embedding_v8.5.trt";
static std::shared_ptr<trt_vehicle::VehicleFeatureEncoder> vehicleEncoder = nullptr;
if (!vehicleEncoder) {
vehicleEncoder = std::make_shared<trt_vehicle::VehicleFeatureEncoder>(feature_model_path);
}
auto vehicle = cv::imread(vehicle_img_path);
std::vector<std::vector<float>> results;
std::vector<cv::Mat> img_datas = {vehicle};
vehicleEncoder->encode(img_datas, results);
for(auto& i : results[0]) {
feature.push_back(i);
}
}
// load all vehicle images (.jpg) from disk and extract all features
void load_vehicle_dataset(std::string dataset_dir,
std::vector<std::pair<std::string, std::vector<float>>>& features_set) {
features_set.clear();
// iterate directory
using recursive_directory_iterator = std::experimental::filesystem::recursive_directory_iterator;
for (const auto& dir_entry : recursive_directory_iterator(dataset_dir))
if (vp_utils::ends_with(dir_entry.path(), ".jpg")) {
std::cout << "load vehicle image: " << dir_entry << std::endl;
// extract single feature
std::vector<float> feature;
extract_feature(dir_entry.path(), feature);
std::pair<std::string, std::vector<float>> p {dir_entry.path(), feature};
features_set.push_back(p);
}
}
void reduce_dims(std::vector<std::pair<std::string, std::vector<float>>>& features_set,
std::vector<std::pair<std::string, std::vector<float>>>& low_dims_features_set,
/* default parameters for t-SNE algorithm */
int no_dims = 2, int max_iter = 1000, double perplexity = 2, double theta = 0.5, int rand_seed = -1, bool skip_random_init = false, int stop_lying_iter = 250, int mom_switch_iter = 250) {
assert(features_set.size() != 0);
auto N = features_set.size();
auto D = features_set[0].second.size(); // all the same as the first feature's dims
// prepare input
double data[N * D];
double Y[N * no_dims];
for (int i = 0; i < N; i++) {
for (int j = 0; j < D; j++) {
data[i * D + j] = features_set[i].second[j];
}
}
// call t-SNE
TSNE::run(data, N, D, Y, no_dims, perplexity, theta, rand_seed, skip_random_init, max_iter, stop_lying_iter, mom_switch_iter);
// prepare output
for (int i = 0; i < N; i++) {
std::vector<float> low_dims_feature;
for (int j = 0; j < no_dims; j++) {
low_dims_feature.push_back(float(Y[i * no_dims + j]));
}
std::pair<std::string, std::vector<float>> p {features_set[i].first, low_dims_feature};
low_dims_features_set.push_back(p);
}
}
int main() {
auto vehicle_dataset_dir = "./vp_data/test_images/vehicle_feature";
auto ft2 = cv::freetype::createFreeType2();
ft2->loadFontData("./vp_data/font/NotoSansCJKsc-Medium.otf", 0);
// load vehicle dataset
std::vector<std::pair<std::string, std::vector<float>>> features_set;
load_vehicle_dataset(vehicle_dataset_dir, features_set);
// reduce dims using t-SNE
std::vector<std::pair<std::string, std::vector<float>>> low_dims_feature_set;
reduce_dims(features_set, low_dims_feature_set);
// print low dims features
std::cout << "low dims features:" << std::endl;
for(auto& i: low_dims_feature_set) {
std::cout << "[" << std::endl;
for(auto& j: i.second) {
std::cout << j << ",";
}
std::cout << "]" << std::endl;
}
// normalize low dims feature to coordinate of [0:1] and display them on 2D screen
auto max_x = 0.0f, max_y = 0.0f, min_x = 0.0f, min_y = 0.0f;
for(auto& i: low_dims_feature_set) {
auto& f = i.second;
// 2 values in f
max_x = std::max(max_x, f[0]);
max_y = std::max(max_y, f[1]);
min_x = std::min(min_x, f[0]);
min_y = std::min(min_y, f[1]);
}
auto x_range = max_x - min_x;
auto y_range = max_y - min_y;
// draw on (canvas_w_h + img_w_h) * (canvas_w_h + img_w_h)
auto canvas_w_h = 800, img_w_h = 70;
cv::Mat canvas(canvas_w_h + img_w_h, canvas_w_h + img_w_h, CV_8UC3, cv::Scalar(127, 127, 127));
for(auto& i: low_dims_feature_set) {
auto& f =i.second;
// convert to [0:1]
f[0] = (f[0] - min_x) / x_range;
f[1] = (f[1] - min_y) / y_range;
auto img = cv::imread(i.first);
cv::Mat img_tmp;
cv::resize(img, img_tmp, cv::Size(img_w_h, img_w_h));
cv::rectangle(img_tmp, cv::Rect(0, 0, img_tmp.cols, img_tmp.rows), cv::Scalar(255, 0, 0));
cv::Mat roi(canvas, cv::Rect(int(f[0] * canvas_w_h), int(f[1] * canvas_w_h), img_w_h, img_w_h));
img_tmp.copyTo(roi);
}
cv::imshow("cluster result", canvas);
cv::waitKey(0);
return 0;
}

View File

@@ -0,0 +1,88 @@
#include <opencv2/core/core.hpp>
#include <opencv2/freetype.hpp>
#include <string>
#include <vector>
#include <map>
#include "../models/vehicle_color_classifier.h"
#include "../models/vehicle_type_classifier.h"
using namespace std;
/*
* vehicle color and vehicle type classifier demo
* tensorRT 8.5 + CUDA 11.1 + cuDNN 8.6 for this code, because original onnx weight could not be converted to TRT engine on tensorRT 7.2
*
* ## color ##
* black
* blue
* grey
* other
* red
* white
* yellow
*
* ## type ##
* bus
* business_car
* construction_truck
* large_truck
* sedan
* small_truck
* suv
* tanker
* van
*/
// to Chinese
std::map<std::string, std::string> types {{"bus", "巴士"},
{"business_car", "商务面包车"},
{"construction_truck", "施工车"},
{"large_truck", "大卡车"},
{"sedan", "轿车"},
{"small_truck", "小卡车"},
{"suv", "SUV"},
{"tanker", "罐车"},
{"van", "厢式货车"}};
int main() {
std::string vehicle_color_model_path = "./vp_data/models/trt/vehicle/vehicle_color_v8.5.trt";
std::string vehicle_type_model_path = "./vp_data/models/trt/vehicle/vehicle_type_v8.5.trt";
std::string font_path = "./vp_data/font/NotoSansCJKsc-Medium.otf";
auto image = cv::imread("./vp_data/test_images/vehicle_cls/1.jpg"); // vehicle in the center of image, crop it first if possible
auto image2 = cv::imread("./vp_data/test_images/vehicle_cls/2.jpg");
auto image3 = cv::imread("./vp_data/test_images/vehicle_cls/3.jpg");
auto image4 = cv::imread("./vp_data/test_images/vehicle_cls/4.jpg");
auto image5 = cv::imread("./vp_data/test_images/vehicle_cls/5.jpg");
auto image6 = cv::imread("./vp_data/test_images/vehicle_cls/6.jpg");
cv::Ptr<cv::freetype::FreeType2> ft2 = cv::freetype::createFreeType2();
ft2->loadFontData(font_path, 0);
auto vehicle_color_classifier = new trt_vehicle::VehicleColorClassifier(vehicle_color_model_path);
auto vehicle_type_classifier = new trt_vehicle::VehicleTypeClassifier(vehicle_type_model_path);
std::vector<cv::Mat> img_datas = {image, image2, image3, image4, image5, image6};
std::vector<trt_vehicle::ObjCls> color_results;
std::vector<trt_vehicle::ObjCls> type_results;
vehicle_color_classifier->classify(img_datas, color_results); // color classify
vehicle_type_classifier->classify(img_datas, type_results); // type classify
for (int i = 0; i < img_datas.size(); i++) {
/* draw class label at top left */
// cv::putText(img_datas[i], color_results[i].label + " " + types.at(type_results[i].label), cv::Point(30, 30), 1, 2, colors.at(color_results[i].label));
ft2->putText(img_datas[i], color_results[i].label + " " + types.at(type_results[i].label), cv::Point(30, 30), 25, cv::Scalar(0, 255, 0), cv::FILLED, cv::LINE_AA, true);
}
cv::imshow("image", image);
cv::imshow("image2", image2);
cv::imshow("image3", image3);
cv::imshow("image4", image4);
cv::imshow("image5", image5);
cv::imshow("image6", image6);
cv::waitKey(0);
delete vehicle_color_classifier;
delete vehicle_type_classifier;
}

View File

@@ -0,0 +1,97 @@
#include <opencv2/core/core.hpp>
#include <opencv2/freetype.hpp>
#include <string>
#include <vector>
#include "../models/vehicle_feature_encoder.h"
using namespace std;
/*
* vehicle comparision demo, 1:1
*/
// compare two features
// dis_type 0 means cosine distance, bigger means more similiar
// dis_type 1 means L2 distance, smaller means more similiar
double match(std::vector<float>& feature1, std::vector<float>& feature2, int dis_type) {
auto _face_feature1 = cv::Mat(1, feature1.size(), CV_32F, feature1.data());
auto _face_feature2 = cv::Mat(1, feature2.size(), CV_32F, feature2.data());
cv::normalize(_face_feature1, _face_feature1);
cv::normalize(_face_feature2, _face_feature2);
if(dis_type == 0) {
return cv::sum(_face_feature1.mul(_face_feature2))[0];
}
else if(dis_type == 1) {
return cv::norm(_face_feature1, _face_feature2);
}
else {
return 0;
}
}
int main() {
std::string featureModelPath = "./vp_data/models/trt/vehicle/vehicle_embedding_v8.5.trt";
auto image = cv::imread("./vp_data/test_images/vehicle_feature/2_001.jpg"); // first vehicle
auto image2 = cv::imread("./vp_data/test_images/vehicle_feature/2_003.jpg"); // second vehicle to compare(the same vehicle with different angle)
auto image3 = cv::imread("./vp_data/test_images/vehicle_feature/5_002.jpg"); // third vehicle to compare(not the same vehicle)
auto vehicleEncoder = new trt_vehicle::VehicleFeatureEncoder(featureModelPath);
auto ft2 = cv::freetype::createFreeType2();
ft2->loadFontData("./vp_data/font/NotoSansCJKsc-Medium.otf", 0);
std::vector<std::vector<float>> results;
std::vector<cv::Mat> img_datas = {image, image2, image3};
vehicleEncoder->encode(img_datas, results); // encode
auto feature1 = results[0];
auto feature2 = results[1];
auto feature3 = results[2];
// print features, 256 dims
auto print_features = [](std::vector<float> features, std::string name) {
std::cout << name << ": " << features.size() << " dims " << "[" << std::endl;
for (auto& i: features) {
std::cout << i << ",";
}
std::cout << "]" << std::endl;
};
print_features(feature1, "feature1");
print_features(feature2, "feature2");
print_features(feature3, "feature3");
auto dis_type = 0;
auto dis_1_2 = match(feature1, feature2, dis_type); // compare feature1 and feature2
auto dis_1_3 = match(feature1, feature3, dis_type); // compare feature1 and feature3
std::cout << "distance between feature1 and feature2: " << dis_1_2 << std::endl;
std::cout << "distance between feature1 and feature3: " << dis_1_3 << std::endl;
// convert to similarity
auto similiarity_1_2 = dis_type == 0 ? dis_1_2 : (1 - dis_1_2);
similiarity_1_2 = std::max(similiarity_1_2, 0.0);
auto similiarity_1_3 = dis_type == 0 ? dis_1_3 : (1 - dis_1_3);
similiarity_1_3 = std::max(similiarity_1_3, 0.0);
// display
auto h = image.rows + std::max(image2.rows, image3.rows) + 50 + 10 + 10;
auto w = std::max(image2.cols, image3.cols) * 2 + 50 + 10 + 10;
cv::Mat canvas(h, w, CV_8UC3,cv::Scalar(127, 127, 127));
cv::Mat roi_(canvas,cv::Rect(canvas.cols / 2 - image.cols / 2, 10, image.cols, image.rows));
cv::Mat roi_2(canvas, cv::Rect(canvas.cols / 2 - image2.cols - 25, 10 + image.rows + 25, image2.cols, image2.rows));
cv::Mat roi_3(canvas, cv::Rect(canvas.cols / 2 + 25, 10 + image.rows + 25, image3.cols, image3.rows));
image.copyTo(roi_);
image2.copyTo(roi_2);
image3.copyTo(roi_3);
cv::line(canvas, cv::Point(canvas.cols / 2, 10 + image.rows), cv::Point(10 + image2.cols / 2, 10 + image.rows + 50), cv::Scalar(255, 0, 0));
cv::line(canvas, cv::Point(canvas.cols / 2, 10 + image.rows), cv::Point(canvas.cols / 2 + 25 + image3.cols / 2, 10 + image.rows + 50), cv::Scalar(255, 0, 0));
ft2->putText(canvas, "相似度:" + std::to_string(similiarity_1_2), cv::Point(10, 10 + image.rows + 25), 20, cv::Scalar(255, 0, 0), cv::FILLED, cv::LINE_AA, true);
ft2->putText(canvas, "相似度:" + std::to_string(similiarity_1_3), cv::Point(10 + image2.cols + 50, 10 + image.rows + 25), 20, cv::Scalar(255, 0, 0), cv::FILLED, cv::LINE_AA, true);
cv::imshow("compare result", canvas);
cv::waitKey(0);
delete vehicleEncoder;
return 0;
}

View File

@@ -0,0 +1,52 @@
#include <opencv2/core/core.hpp>
#include <opencv2/freetype.hpp>
#include <string>
#include <vector>
#include "../models/vehicle_plate_detector.h"
using namespace std;
/*
* vehicle plate demo
*/
std::map<std::string, cv::Scalar> colors {{"blue", cv::Scalar(255, 0, 0)},
{"green", cv::Scalar(0, 255, 0)},
{"yellow", cv::Scalar(0, 255, 255)},
{"white", cv::Scalar(255, 255, 255)}};
int main(){
std::string plateModelPath = "./vp_data/models/trt/plate/det_v8.5.trt";
std::string charModelPath = "./vp_data/models/trt/plate/rec_v8.5.trt";
auto image = cv::imread("./vp_data/test_images/plates/0.jpg");
auto image2 = cv::imread("./vp_data/test_images/plates/1.jpg");
auto image3 = cv::imread("./vp_data/test_images/plates/2.jpg");
auto plateDetector = new trt_vehicle::VehiclePlateDetector(plateModelPath, charModelPath);
auto ft2 = cv::freetype::createFreeType2();
ft2->loadFontData("./vp_data/font/NotoSansCJKsc-Medium.otf", 0);
std::vector<std::vector<trt_vehicle::Plate>> results;
std::vector<cv::Mat> img_datas = {image, image2, image3};
plateDetector->detect(img_datas, results, true);
for (int i = 0; i < results.size(); i++) {
/* code */
for (int j = 0; j < results[i].size(); j++)
{
/* code */
auto& plate = results[i][j];
cv::rectangle(img_datas[i], cv::Rect(plate.x, plate.y, plate.width, plate.height), colors.at(plate.color), 2);
//cv::putText(img_datas[i], plate.text, cv::Point(plate.x, plate.y), 1, 0.8, colors.at(plate.color));
ft2->putText(img_datas[i], plate.text, cv::Point(plate.x, plate.y), 20, colors.at(plate.color), cv::FILLED, cv::LINE_AA, true);
}
}
cv::imshow("image", image);
cv::imshow("image2", image2);
cv::imshow("image3", image3);
cv::waitKey(0);
delete plateDetector;
return 0;
}

View File

@@ -0,0 +1,53 @@
#include <opencv2/core/core.hpp>
#include <string>
#include <vector>
#include <map>
#include "../models/vehicle_scanner.h"
using namespace std;
/*
* vehicle scan demo, detect on vehicle body
* tensorRT 8.5 + CUDA 11.1 + cuDNN 8.6 for this code, because original onnx weight could not be converted to TRT engine on tensorRT 7.2
*/
std::map<std::string, cv::Scalar> colors {{"truck", cv::Scalar(255, 0, 0)}, // 货车
{"bus", cv::Scalar(0, 255, 255)}, //巴士
{"car", cv::Scalar(0, 255, 0)}, //轿车
{"suv", cv::Scalar(0, 255, 0)}, //suv+商务
{"van", cv::Scalar(0, 255, 0)}, //面包+金杯
{"nowindow", cv::Scalar(0, 255, 0)}, //封窗货车,货拉拉
{"iveco", cv::Scalar(0, 255, 0)}, //9座依维柯
{"pickup", cv::Scalar(0, 255, 0)}, //皮卡
{"wheel", cv::Scalar(0, 255, 0)}}; //轮子
int main() {
std::string vehicle_scan_model_path = "./vp_data/models/trt/vehicle/vehicle_scan_v8.5.trt";
auto image = cv::imread("./vp_data/test_images/body/0.jpg");
auto image2 = cv::imread("./vp_data/test_images/body/1.jpg");
auto vehicle_scanner = new trt_vehicle::VehicleScanner(vehicle_scan_model_path);
std::vector<cv::Mat> img_datas = {image, image2};
std::vector<std::vector<trt_vehicle::ObjBox>> results;
vehicle_scanner->detect(img_datas, results);
for (int i = 0; i < results.size(); i++)
{
/* code */
for (int j = 0; j < results[i].size(); j++)
{
/* code */
auto& objbox = results[i][j];
cv::rectangle(img_datas[i], cv::Rect(objbox.x, objbox.y, objbox.width, objbox.height), colors.at(objbox.label), 2);
cv::putText(img_datas[i], objbox.label + std::to_string(objbox.score), cv::Point(objbox.x, objbox.y), 1, 0.8, colors.at(objbox.label));
}
}
cv::imshow("image", image);
cv::imshow("image2", image2);
cv::waitKey(0);
delete vehicle_scanner;
}

View File

@@ -0,0 +1,150 @@
#include <opencv2/core/core.hpp>
#include <opencv2/freetype.hpp>
#include <string>
#include <vector>
#include <memory>
#include <experimental/filesystem>
#include "../models/vehicle_feature_encoder.h"
#include "../../../utils/vp_utils.h"
using namespace std;
/*
* vehicle search demo, 1:N
*/
// compare two features
// dis_type 0 means cosine distance, bigger means more similiar
// dis_type 1 means L2 distance, smaller means more similiar
double match(std::vector<float>& feature1, std::vector<float>& feature2, int dis_type) {
auto _face_feature1 = cv::Mat(1, feature1.size(), CV_32F, feature1.data());
auto _face_feature2 = cv::Mat(1, feature2.size(), CV_32F, feature2.data());
cv::normalize(_face_feature1, _face_feature1);
cv::normalize(_face_feature2, _face_feature2);
if(dis_type == 0) {
return cv::sum(_face_feature1.mul(_face_feature2))[0];
}
else if(dis_type == 1) {
return cv::norm(_face_feature1, _face_feature2);
}
else {
return 0;
}
}
// extract feature for vehicle
void extract_feature(std::string vehicle_img_path, std::vector<float>& feature) {
static std::string feature_model_path = "./vp_data/models/trt/vehicle/vehicle_embedding_v8.5.trt";
static std::shared_ptr<trt_vehicle::VehicleFeatureEncoder> vehicleEncoder = nullptr;
if (!vehicleEncoder) {
vehicleEncoder = std::make_shared<trt_vehicle::VehicleFeatureEncoder>(feature_model_path);
}
auto vehicle = cv::imread(vehicle_img_path);
std::vector<std::vector<float>> results;
std::vector<cv::Mat> img_datas = {vehicle};
vehicleEncoder->encode(img_datas, results);
for(auto& i : results[0]) {
feature.push_back(i);
}
}
// load all vehicle images (.jpg) from disk and extract all features
void load_vehicle_dataset(std::string dataset_dir,
std::vector<std::pair<std::string, std::vector<float>>>& features_set) {
features_set.clear();
// iterate directory
using recursive_directory_iterator = std::experimental::filesystem::recursive_directory_iterator;
for (const auto& dir_entry : recursive_directory_iterator(dataset_dir))
if (vp_utils::ends_with(dir_entry.path(), ".jpg")) {
std::cout << "load vehicle image: " << dir_entry << std::endl;
// extract single feature
std::vector<float> feature;
extract_feature(dir_entry.path(), feature);
std::pair<std::string, std::vector<float>> p {dir_entry.path(), feature};
features_set.push_back(p);
}
}
// match features using query feature, sorted by similiarity
void search(std::vector<float>& query_feature,
std::vector<std::pair<std::string, std::vector<float>>>& features_set,
std::vector<std::pair<std::string, float>>& query_result,
int dis_type = 0,
int top_n = 0) {
query_result.clear();
// just loop the features set
for (auto& i: features_set) {
/* code */
auto dis = match(i.second, query_feature, dis_type);
std::pair<std::string, float> p {i.first, dis};
query_result.push_back(p);
}
// sort from high to low
sort(query_result.begin(), query_result.end(), [=](std::pair<std::string, float>& a, std::pair<std::string, float>& b)
{
return a.second > b.second;
});
}
int main() {
auto vehicle_dataset_dir = "./vp_data/test_images/vehicle_feature";
auto query_vehicle_path = "./vp_data/test_images/vehicle_feature/7_002.jpg";
auto ft2 = cv::freetype::createFreeType2();
ft2->loadFontData("./vp_data/font/NotoSansCJKsc-Medium.otf", 0);
// load vehicle dataset
std::vector<std::pair<std::string, std::vector<float>>> features_set;
load_vehicle_dataset(vehicle_dataset_dir, features_set);
// load query vehicle
std::vector<float> query_feature;
extract_feature(query_vehicle_path, query_feature);
// search it!
std::vector<std::pair<std::string, float>> query_result;
search(query_feature, features_set, query_result, 0, 10);
// print similiarity from high to low
for(auto& i: query_result) {
std::cout << i.second << " ==> " << i.first << std::endl;
}
// display according to query_result
auto n_query = query_result.size();
auto rect_w_h = 80; auto gap = 20; auto cols = 10;
auto rows = n_query / cols + 2;
// create canvas
cv::Mat canvas(rows * (rect_w_h + gap) + gap, cols * (rect_w_h + gap) + gap, CV_8UC3,cv::Scalar(127, 127, 127));
// query vehicle at first line
cv::Mat roi_query = cv::Mat(canvas, cv::Rect(gap, gap, rect_w_h, rect_w_h));
auto query_vehicle_img = cv::imread(query_vehicle_path);
cv::Mat query_vehicle_img_tmp;
cv::resize(query_vehicle_img, query_vehicle_img_tmp, cv::Size(rect_w_h, rect_w_h));
query_vehicle_img_tmp.copyTo(roi_query);
ft2->putText(canvas, "query vehicle:", cv::Point(20, 14), 14, cv::Scalar(255, 0, 0), cv::FILLED, cv::LINE_AA, true);
// query result
for(int i = 0; i < query_result.size(); ++i) {
auto row = i / cols + 1;
auto col = i % cols;
cv::Mat roi = cv::Mat(canvas, cv::Rect(gap + col * (rect_w_h + gap), gap + row * (rect_w_h + gap), rect_w_h, rect_w_h));
auto vehicle_img = cv::imread(query_result[i].first);
cv::Mat vehicle_img_tmp;
cv::resize(vehicle_img, vehicle_img_tmp, cv::Size(rect_w_h, rect_w_h));
vehicle_img_tmp.copyTo(roi);
ft2->putText(canvas, std::to_string(std::max(query_result[i].second, 0.0f)), cv::Point(gap + col * (rect_w_h + gap), row * (rect_w_h + gap) + gap), 14, cv::Scalar(255, 0, 0), cv::FILLED, cv::LINE_AA, true);
}
cv::imshow("search result", canvas);
cv::waitKey(0);
return 0;
}