RMVL  1.0.0
RoboMaster Vision Library
samples/detector/hik/sample_hik_armor_size_classify.cpp

大小装甲板分类例程

#include <iostream>
#include <thread>
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>
using namespace rm;
using namespace para;
using namespace std;
using namespace cv;
int wait_time = 1;
int collect_num = 2000;
capture_ptr capture; // 相机
auto p_detector = ArmorDetector::make_detector(); // 识别模块
Mat frame; // 帧图像
vector<group_ptr> groups; // 序列组列表
Mat armor_samples; // 装甲板信息样本
Mat armor_responses; // 装甲板响应/标签
void collect(PixChannel color, ArmorSizeType type, int begin_idx)
{
for (int idx = 0; idx < collect_num; ++idx)
{
capture->read(frame);
if (frame.empty())
RMVL_Error(RMVL_StsBadSize, "frame is empty, something wrong with the camera.");
auto info = p_detector->detect(groups, frame, color, GyroData(), getTickCount());
const auto &combos = info.combos;
if (combos.size() != 1)
{
if (combos.size() > 1)
WARNING_("Size of the combos is greater than 1, size = %zu", combos.size());
idx--;
}
else
{
auto p_armor = Armor::cast(combos.front());
// 收集数据
armor_samples.at<float>(begin_idx + idx, 0) = p_armor->getComboRatio(); // 装甲板长宽比
armor_samples.at<float>(begin_idx + idx, 1) = p_armor->getWidthRatio(); // 灯条宽度比
armor_samples.at<float>(begin_idx + idx, 2) = p_armor->getLengthRatio(); // 灯条长度比
armor_responses.at<int>(begin_idx + idx) = type == ArmorSizeType::SMALL ? 1 : 2;
const auto &corners = p_armor->getCorners();
for (int i = 0; i < 4; ++i)
line(frame, corners[i], corners[(i + 1) % 4], Scalar(0, 255, 0), 2);
}
putText(frame, to_string(idx), Point(20, 50), FONT_HERSHEY_COMPLEX, 1.0, Scalar(255, 255, 255), 1);
imshow("信息收集", frame);
int ch = waitKey(wait_time);
if (ch == 27)
waitKey(0);
else if (ch == 113) // 'q'
exit(0);
}
}
const char *keys = "{ ? h help | | 帮助信息 }"
"{ m model | | 模型路径,这将跳过训练直接进行测试 }"
"{ n num |2000 | 每种装甲板收集的数量 }"
"{ w waitkey |1 | cv::waitKey(?) }"
"{ c color |0 | 识别装甲板颜色 '\033[33m0\033[0m': 识别蓝色,"
"'\033[33m1\033[0m': 识别红色 }";
const char *help = " \033[34;1m使用说明\033[0m\n"
"程序会收集大小装甲板数据各 'num' 张(默认为 2000 张),通过采集\n1) "
"装甲板长宽比 combo_ratio\n2) 灯条宽度比 width_ratio\n3) 灯条长度比 "
"length_ratio\n5) 共 3 个指标特征,进行 SVM 二分类,分类后的结果将自"
"动\n导出至 \033[33mout_armor_size.xml\033[0m 中";
int main(int argc, const char *argv[])
{
// 命令行参数初始化
CommandLineParser parser(argc, argv, keys);
if (parser.has("help"))
{
parser.printMessage();
cout << help << endl;
exit(0);
}
// 获取命令行参数
PixChannel color = parser.get<int>("color") == 0 ? PixChannel::BLUE : PixChannel::RED;
string model;
if (parser.has("model"))
model = parser.get<string>("model");
collect_num = parser.get<int>("num");
wait_time = parser.get<int>("waitkey");
armor_samples = Mat::zeros(collect_num * 2, 3, CV_32FC1);
armor_responses = Mat::zeros(collect_num * 2, 1, CV_32SC1);
// 设置相机参数
if (!capture->isOpened())
{
printf("相机打开失败\n");
return -1;
}
int exposure = 3000;
int gain = 8;
int r_gain = 1500;
int g_gain = 1500;
int b_gain = 1500;
FileStorage fs_mv_set("out_para.yml", FileStorage::READ);
if (fs_mv_set.isOpened())
{
readExcludeNone(fs_mv_set["exposure"], exposure);
readExcludeNone(fs_mv_set["gain"], gain);
readExcludeNone(fs_mv_set["r_gain"], r_gain);
readExcludeNone(fs_mv_set["g_gain"], g_gain);
readExcludeNone(fs_mv_set["b_gain"], b_gain);
}
capture->set(CAP_PROP_RM_MANUAL_EXPOSURE, 0);
capture->set(CAP_PROP_RM_EXPOSURE, exposure);
capture->set(CAP_PROP_RM_GAIN, gain);
capture->set(CAP_PROP_RM_MANUAL_WB, 0);
capture->set(CAP_PROP_RM_WB_RGAIN, r_gain);
capture->set(CAP_PROP_RM_WB_GGAIN, g_gain);
capture->set(CAP_PROP_RM_WB_BGAIN, b_gain);
cv::Ptr<cv::ml::SVM> p_svm = nullptr;
if (model.empty())
{
cout << "=======================================" << endl;
// --------------------- 小装甲板收集 ---------------------
string key_str;
cout << "\033[32m小装甲板\033[0m信息收集即将开始..." << endl;
cout << "输入 \033[33;1mok\033[0m 来开始收集 >>> ";
cin >> key_str;
if (key_str != "ok")
return 0;
collect(color, ArmorSizeType::SMALL, 0);
destroyAllWindows();
this_thread::sleep_for(chrono::milliseconds(10));
// --------------------- 大装甲板收集 ---------------------
cout << "\033[32m大装甲板\033[0m信息收集即将开始..." << endl;
cout << "输入 \033[33;1mok\033[0m 来开始收集 >>> ";
cin >> key_str;
if (key_str != "ok")
return 0;
collect(color, ArmorSizeType::BIG, collect_num);
destroyAllWindows();
this_thread::sleep_for(chrono::milliseconds(10));
// 训练与分类
p_svm = ml::SVM::create();
p_svm->setType(ml::SVM::C_SVC);
p_svm->setKernel(ml::SVM::RBF);
if (p_svm->train(armor_samples, ml::ROW_SAMPLE, armor_responses))
p_svm->save("out_armor_size.xml"); // 导出模型
else
RMVL_Error(RMVL_StsError, "Failed to train the SVM.");
// 测试
cout << "想要进行测试吗?" << endl;
cout << "输入 \033[33;1mok\033[0m 来进行测试 >>> ";
cin >> key_str;
if (key_str != "ok")
return 0;
}
else
{
p_svm = ml::SVM::load(model);
}
cout << "在键盘上按下一次 \033[33mEsc\033[0m 来暂停,按下两次 \033[33mEsc\033[0m 来退出测试" << endl;
while (capture->read(frame))
{
auto info = p_detector->detect(groups, frame, color, GyroData(), getTickCount());
const auto &combos = info.combos;
if (!combos.empty())
{
if (combos.size() > 1)
WARNING_("Size of the combos is greater than 1, size = %zu", combos.size());
auto p_armor = Armor::cast(combos.front());
// 收集数据
Matx13f test_sample;
test_sample(0) = p_armor->getComboRatio(); // 装甲板长宽比
test_sample(1) = p_armor->getWidthRatio(); // 灯条宽度比
test_sample(2) = p_armor->getLengthRatio(); // 灯条长度比
// 测试
float result = p_svm->predict(test_sample);
putText(frame, result == 1 ? "SMALL" : "BIG", Point(20, 50),
FONT_HERSHEY_COMPLEX, 1.0, Scalar(255, 255, 255), 2);
const auto &corners = p_armor->getCorners();
for (int i = 0; i < 4; ++i)
line(frame, corners[i], corners[(i + 1) % 4], Scalar(0, 255, 0), 2);
}
imshow("模型测试", frame);
if (waitKey(wait_time) == 27)
if (waitKey(0) == 27)
break;
}
return 0;
}
static std::unique_ptr< ArmorDetector > make_detector()
构建 ArmorDetector
Definition: armor_detector.h:75
static std::shared_ptr< Armor > cast(combo_ptr p_combo)
动态类型转换
Definition: armor.h:68
static std::unique_ptr< HikVideoCapture > make_capture(GrabMode grab_mode, RetrieveMode retrieve_mode, std::string_view serial="")
构建 HikVideoCapture 对象 Construct HikVideoCapture object
Definition: hik_video_capture.h:76
装甲板识别派生类头文件
std::unique_ptr< cv::VideoCapture > capture_ptr
Definition: camera_define.h:24
@ CAP_PROP_RM_WB_BGAIN
白平衡蓝色分量 Blue channel gain of white balance
Definition: camera_define.h:63
@ CAP_PROP_RM_WB_RGAIN
白平衡红色分量 Red channel gain of white balance
Definition: camera_define.h:61
@ CAP_PROP_RM_EXPOSURE
曝光值 Expusure
Definition: camera_define.h:58
@ CAP_PROP_RM_MANUAL_EXPOSURE
手动曝光 Manual exposure
Definition: camera_define.h:56
@ CAP_PROP_RM_GAIN
模拟增益 Analog gain
Definition: camera_define.h:59
@ CAP_PROP_RM_MANUAL_WB
手动白平衡 Manual white balance
Definition: camera_define.h:57
@ CAP_PROP_RM_WB_GGAIN
白平衡绿色分量 Green channel gain of white balance
Definition: camera_define.h:62
@ RETRIEVE_CV
使用 OpenCV 的 'cvtColor' 进行处理 Retrieve using cvtColor function in OpenCV
Definition: camera_define.h:39
@ GRAB_CONTINUOUS
连续采样 Continuous grabbing
Definition: camera_define.h:29
#define WARNING_(msg...)
Definition: util.hpp:35
#define RMVL_Error(code, msg)
调用错误处理程序
Definition: util.hpp:204
@ RMVL_StsBadSize
数组大小不正确 Incorrect size of the array
Definition: util.hpp:87
@ RMVL_StsError
未指定(未知)错误 Unspecified (Unknown) error
Definition: util.hpp:84
PixChannel
像素通道枚举
Definition: pretreat.h:24
@ RED
红色通道
Definition: pretreat.h:27
@ BLUE
蓝色通道
Definition: pretreat.h:25
void readExcludeNone(const _FileNode &n, Tp &t)
参数读取,忽略为空的节点
Definition: loader.hpp:41
void load(Tp &para_obj, const std::string &file_path)
参数加载
Definition: loader.hpp:32
ArmorSizeType
装甲板大小类型
Definition: types.hpp:27
@ SMALL
小装甲板
@ BIG
大装甲板
Hik Robot 工业相机库
Definition: uty_math.hpp:63
Definition: camera.hpp:23
Definition: camera_define.h:19