diff --git a/.vscode/launch.json b/.vscode/launch.json index 1741c5e..79ce621 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,7 +8,7 @@ { "name": "(gdb) Launch", /* 配置名称,将会在启动配置的下拉菜单中显⽰ */ - "preLaunchTask": "build", /* 调试前执⾏ 'build'选项 */ + // "preLaunchTask": "build", /* 调试前执⾏ 'build'选项 */ "type": "cppdbg", /* 配置类型,这⾥只能为cppdbg */ "request": "launch",/**/ "program": "${workspaceFolder}/run.o", /*选择要调试的⽂件路径*/ diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 93af57b..a2df583 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,11 +7,11 @@ "command": "/usr/bin/g++", /* 这⾥填写你的编译器地址 */ "args": [ /* 类似与qt的Pro⽂件⾥开始的那⼏句 */ - "-Ofast", - "-march=native", - "-flto", - "-frename-registers", - "-std=c++11",// 静态链接 + // "-Ofast", + // "-march=native", + // "-flto", + // "-frename-registers", + "-std=c++14",// 静态链接 "-static-libgcc", "-lpthread", @@ -31,6 +31,7 @@ "-I","${workspaceFolder}/module/RM_Buff/Target", "-I","${workspaceFolder}/module/RM_Buff", "-I","${workspaceFolder}/module/top_detect", + "-I","${workspaceFolder}/module/orc", "-I","${workspaceFolder}/base", "-I","/usr/local/include", "-I","/usr/local/include/opencv4", @@ -52,6 +53,7 @@ "${workspaceFolder}/module/RM_Buff/Target/Target.cpp", "${workspaceFolder}/module/RM_Buff/RM_Buff.cpp", "${workspaceFolder}/module/top_detect/top.cpp", + "${workspaceFolder}/module/orc/orc.cpp", "${workspaceFolder}/base/connector.cpp", "${workspaceFolder}/user/main.cpp",/* ${workspaceFolder}表⽰路径从当前项⽬⽂件夹开始 */ "-o", /* 编译输出⽂件的存放路径 */ diff --git a/base/connector.cpp b/base/connector.cpp index 18a3fd4..3184cbd 100644 --- a/base/connector.cpp +++ b/base/connector.cpp @@ -5,6 +5,7 @@ Connector::Connector() {} Connector::~Connector() {} void Connector::run() { + model module_("mnist-8.onnx"); while (true) { if (mv_capture_.isindustryimgInput()) { src_img_ = mv_capture_.image(); @@ -40,7 +41,7 @@ void Connector::run() { mv_capture_.cameraReleasebuff(); armor_.free_Memory(); // usleep(1); - if (cv::waitKey(1) == 'q') { + if (cv::waitKey(0) == 'q') { return; } } diff --git a/base/connector.hpp b/base/connector.hpp index f30c55d..ee405e4 100644 --- a/base/connector.hpp +++ b/base/connector.hpp @@ -6,19 +6,28 @@ #include "module/RM_Buff/RM_Buff.hpp" #include "module/angle_solve/rm_solve_pnp.hpp" #include "module/armor/rm_armor.hpp" + + class Connector { private: cv::Mat src_img_; - mv_camera::RM_VideoCapture mv_capture_ = + + mv_camera::RM_VideoCapture mv_capture_ =//初始相机的结构体 mv_camera::RM_VideoCapture(mv_camera::CameraParam( - 1, mv_camera::RESOLUTION_1280_X_800, mv_camera::EXPOSURE_600)); + 1, mv_camera::RESOLUTION_1280_X_800, mv_camera::EXPOSURE_600)); + armor::RM_ArmorDetector armor_ = armor::RM_ArmorDetector("module/armor/armor_config.xml"); + serial_port::SerialPort serial_ = serial_port::SerialPort("devices/serial/serial_config.xml"); + buff::RM_Buff buff_ = buff::RM_Buff("module/RM_Buff/Config/buff_config.xml"); + cv::VideoCapture cap_ = - cv::VideoCapture("/home/xx/下载/视频/效果图/camera_MaxBuff18.avi"); + cv::VideoCapture("/home/sms/VIDEO/camera_MaxBuff15.avi"); + + public: void run(); diff --git a/mnist-8.onnx b/mnist-8.onnx new file mode 100644 index 0000000..fc1a3f7 Binary files /dev/null and b/mnist-8.onnx differ diff --git a/module/armor/armor_config.xml b/module/armor/armor_config.xml index a1d4f8f..2375ebf 100644 --- a/module/armor/armor_config.xml +++ b/module/armor/armor_config.xml @@ -64,6 +64,10 @@ 30 255 + + + + diff --git a/module/armor/rm_armor.cpp b/module/armor/rm_armor.cpp index 43254ef..cc0e191 100644 --- a/module/armor/rm_armor.cpp +++ b/module/armor/rm_armor.cpp @@ -26,7 +26,10 @@ RM_ArmorDetector::RM_ArmorDetector(std::string _armor_config) { fs_armor["S_BLUE_MAX"] >> image_config_.s_blue_max; fs_armor["V_BLUE_MIN"] >> image_config_.v_blue_min; fs_armor["V_BLUE_MAX"] >> image_config_.v_blue_max; + + } + fs_armor["LIGHT_DRAW"] >> light_config_.light_draw; fs_armor["LIGHT_EDTI"] >> light_config_.light_edit; fs_armor["LIGHT_RATIO_W_H_MIN"] >> light_config_.ratio_w_h_min; @@ -57,6 +60,8 @@ RM_ArmorDetector::RM_ArmorDetector(std::string _armor_config) { std::cout << "装甲板参数初始化成功" << std::endl; std::cout << "💚💚💚💚💚💚💚💚💚💚💚💚" << std::endl; + + } /** @@ -162,8 +167,9 @@ bool RM_ArmorDetector::find_Light() { * @return false 无法得到装甲板 */ serial_port::Write_Data RM_ArmorDetector::run_Armor( - cv::Mat &_src_img, serial_port::Receive_Data _receive_data) { + cv::Mat &_src_img, serial_port::Receive_Data _receive_data ) { //图像处理 + frame = _src_img.clone(); run_Image(_src_img, _receive_data.my_color); draw_img_ = _src_img; if (find_Light()) { @@ -180,6 +186,9 @@ serial_port::Write_Data RM_ArmorDetector::run_Armor( if (armor_config_.armor_draw == 1 || light_config_.light_draw == 1 || armor_config_.armor_edit == 1 || light_config_.light_edit == 1) { + cv::putText(draw_img_,to_string( pnp_.returnDepth()), + cv::Point(50,100),cv::FONT_HERSHEY_SIMPLEX,1, + cv::Scalar(0,255,255),1,cv::LINE_AA); imshow("armor_draw_img", draw_img_); draw_img_ = cv::Mat::zeros(_src_img.size(), CV_8UC3); } @@ -191,6 +200,7 @@ serial_port::Write_Data RM_ArmorDetector::run_Armor( } if (armor_config_.armor_draw == 1 || light_config_.light_draw == 1 || armor_config_.armor_edit == 1 || light_config_.light_edit == 1) { + imshow("armor_draw_img", draw_img_); draw_img_ = cv::Mat::zeros(_src_img.size(), CV_8UC3); } @@ -199,6 +209,79 @@ serial_port::Write_Data RM_ArmorDetector::run_Armor( pnp_.returnYawAngle(), cv::Point(0, 0)), pnp_.returnPitchAngle(), pnp_.returnDepth(), armor_.size(), 0); } + + + +/*********number*********************/ + +cv::Mat RM_ArmorDetector::Save_ROI(cv::Rect input_rect , cv::Mat img_input) +{ + cv::Point Point_t;int width_ ,height_; + Point_t.x = input_rect.x + 10; + Point_t.y = input_rect.y - 30; + width_ = input_rect.width -20; + height_ = input_rect.height +50; +if(Point_t.x < 0) +{ + Point_t.x = 0 ; +} +if(Point_t.y < 0) +{ + Point_t.y = 0; +} +if(Point_t.x+width_ > img_input.cols) +{ + width_ = img_input.cols - abs(Point_t.x); +} +if(Point_t.y+height_ > img_input.rows) +{ + height_ = img_input.rows - abs(Point_t.y); +} + +return img_input(cv::Rect(Point_t,cv::Size(width_,height_))); + +} + + +bool RM_ArmorDetector::NumberOrc() +{ + + cv::namedWindow("数字number"); + cv::createTrackbar("h_min_num", "数字number",&OrcCtrl_.num_cfg_.h_min_num, + 255, NULL); + cv::createTrackbar("s_min_num", "数字number", + &OrcCtrl_.num_cfg_.s_min_num, 255, NULL); + cv::createTrackbar("v_min_num", "数字number", + &OrcCtrl_.num_cfg_.v_min_num, 255, NULL); + + cv::createTrackbar("CONFIDENT", "数字number", + &OrcCtrl_.num_cfg_.Confident, 5000, NULL);//置信度 + cv::createTrackbar("kernel_size", "数字number", + &OrcCtrl_.num_cfg_.kennerl_size, 10, NULL);//置信度 + + cv::Mat Number_img = Save_ROI(armor_data_.armor_rect.boundingRect(),frame); + int k =module_.inferring(Number_img, + 2*OrcCtrl_.num_cfg_.kennerl_size-1, + cv::Scalar(OrcCtrl_.num_cfg_.h_min_num,OrcCtrl_.num_cfg_.s_min_num,OrcCtrl_.num_cfg_.v_min_num), + cv::Scalar(255,255,255),OrcCtrl_.num_cfg_.Confident); + if(OrcCtrl_.num_cfg_.switch_number == 1) + { + putText( frame, to_string(k), cv::Point(100, 100), 5, 5.0 ,cv::Scalar(0,360,360), + 2, cv::LINE_8, false ); + cv::imshow("frame_number",frame); + cv::imshow("number",Number_img); + } + + + if(k == 2) + { + return false; + }else{ + return true; + } +} + +/*********number*********************/ /** * @brief 求两点之间的距离 * @@ -323,7 +406,7 @@ bool RM_ArmorDetector::fitting_Armor() { * @return true 找到了符合装甲板条件的位置 * @return false 没找到了符合装甲板条件的位置 */ -bool RM_ArmorDetector::light_Judge(int i, int j) { +bool RM_ArmorDetector::light_Judge(int i, int j ) { armor_data_.left_light_height = MAX(light_[i].size.height, light_[i].size.width); armor_data_.left_light_width = @@ -344,7 +427,8 @@ bool RM_ArmorDetector::light_Judge(int i, int j) { armor_data_.light_width_aspect < (armor_config_.light_width_ratio_max * 0.1) && armor_data_.light_width_aspect > - (armor_config_.light_height_ratio_min * 0.1)) { + (armor_config_.light_height_ratio_min * 0.1)) + { armor_data_.height = (armor_data_.left_light.size.height + armor_data_.right_light.size.height) / 2; @@ -377,12 +461,31 @@ bool RM_ArmorDetector::light_Judge(int i, int j) { (armor_config_.small_armor_aspect_min * 0.1) && (armor_data_.aspect_ratio < armor_config_.armor_type_th * 0.1)) { armor_data_.distinguish = 0; // 小装甲板 - return true; + + + if(NumberOrc()) + { + if(OrcCtrl_.num_cfg_.switch_number == 1) + { + cv::putText(draw_img_,"SMALL",cv::Point(50,50),cv::FONT_HERSHEY_SIMPLEX,2, + cv::Scalar(255,255,255),2,cv::LINE_AA); + } + return true; + }else + { + return false; + } } else if (armor_data_.aspect_ratio > (armor_config_.armor_type_th * 0.1) && armor_data_.aspect_ratio < - (armor_config_.big_armor_aspect_max * 0.1)) { - armor_data_.distinguish = 1; //大装甲板 + (armor_config_.big_armor_aspect_max * 0.1)){ + armor_data_.distinguish = 1; //大装甲板 + NumberOrc(); + if(OrcCtrl_.num_cfg_.switch_number == 1) + { + cv::putText(draw_img_,"BIG",cv::Point(50,50),cv::FONT_HERSHEY_SIMPLEX,2, + cv::Scalar(255,255,255),2,cv::LINE_AA); + } return true; } } diff --git a/module/armor/rm_armor.hpp b/module/armor/rm_armor.hpp index 16a894f..ebbcee3 100644 --- a/module/armor/rm_armor.hpp +++ b/module/armor/rm_armor.hpp @@ -8,6 +8,9 @@ #include "module/angle_solve/rm_solve_pnp.hpp" #include "module/filter/filter.hpp" #include "module/top_detect/top.hpp" +#include "module/orc/orc.hpp" +#include "opencv_onnx_inferring.hpp" + namespace armor { struct Armor_Data { @@ -48,6 +51,7 @@ struct Armor_Cfg { int small_armor_aspect_min; int armor_type_th; int big_armor_aspect_max; + }; struct Light_Cfg { @@ -88,7 +92,12 @@ struct Image_Cfg { int gray_edit = 0; int color_edit = 0; int method = 0; + + + }; + + /** * @brief 图像处理 * @@ -97,14 +106,23 @@ class RM_ArmorDetector { //装甲板 public: serial_port::Write_Data run_Armor(cv::Mat &_src_img, - serial_port::Receive_Data _receive_data); - bool light_Judge(int i, int j); //判断左右灯条能否组成装甲板 + serial_port::Receive_Data _receive_data ); + bool light_Judge(int i, int j ); //判断左右灯条能否组成装甲板 int average_Color(); //计算图像颜色平均值 bool fitting_Armor(); //拟合装甲板 bool find_Light(); //寻找灯条 void final_Armor(); //最优装甲板 void free_Memory(); //释放内存 - int motion_Direction(); //判断装甲板运动方向 + int motion_Direction(); //判断装甲板运动方向 + +/****************数字*************************/ + + bool NumberOrc(); + cv::Mat Save_ROI( cv::Rect input_rect , cv::Mat img_input); + +/****************数字*************************/ + + inline Armor_Data returnFinalArmor(int _num) { return armor_[_num]; } inline cv::Point returnFinalArmorCenter(int _num) { return armor_[num].armor_rect.center; @@ -136,6 +154,10 @@ class RM_ArmorDetector { Image_Cfg image_config_; Light_Cfg light_config_; + + Orc::OrcNumber OrcCtrl_ = Orc::OrcNumber("module/orc/orc_config.xml"); + model module_ = model("mnist-8.onnx"); + cv::Mat frame; //原图 cv::Mat draw_img_; //画板 cv::Mat gray_img_; @@ -173,6 +195,7 @@ class RM_ArmorDetector { int armor_direction = 0; // 1向右 -1 向左 int num = 0; //运行次数 + //图像 private: cv::Mat gray_trackbar_ = cv::Mat::zeros(1, 300, CV_8UC1); diff --git a/module/orc/orc.cpp b/module/orc/orc.cpp new file mode 100644 index 0000000..ff38a73 --- /dev/null +++ b/module/orc/orc.cpp @@ -0,0 +1,25 @@ +#include "orc.hpp" + +namespace Orc +{ + OrcNumber::OrcNumber(){} + + OrcNumber::OrcNumber(std::string Orc_config_) + { + cv::FileStorage Orc_armor(Orc_config_, cv::FileStorage::READ); + Orc_armor["H_MIN_NUM"] >> num_cfg_.h_min_num; + Orc_armor["H_MAX_NUM"] >> num_cfg_.h_max_num; + Orc_armor["S_MIN_NUM"] >> num_cfg_.s_min_num; + Orc_armor["S_MAX_NUM"] >> num_cfg_.s_max_num; + Orc_armor["V_MIN_NUM"] >> num_cfg_.v_min_num; + Orc_armor["V_MAX_NUM"] >> num_cfg_.v_max_num; + Orc_armor["CONFIDENT"] >> num_cfg_.Confident; + Orc_armor["KERNEL_SIZE"] >> num_cfg_.kennerl_size; + + Orc_armor["NUMBER_SWITCH"] >> num_cfg_.switch_number; + } + OrcNumber::~OrcNumber(){} + + +} // namespace Orc + diff --git a/module/orc/orc.hpp b/module/orc/orc.hpp new file mode 100644 index 0000000..70579bc --- /dev/null +++ b/module/orc/orc.hpp @@ -0,0 +1,53 @@ + +#ifndef _USE_ORCNUMBER_ +#define _USE_ORCNUMBER_ + + +#include +#include +#include"opencv_onnx_inferring.hpp" + + +namespace Orc +{ +struct Number_Cfg { + + int h_min_num; + int h_max_num; + + int s_min_num ; + int s_max_num; + + int v_min_num; + int v_max_num; + + int Confident; + int kennerl_size ; + + int switch_number; + + +}; + + class OrcNumber + { + private: + /* data */ + public: + OrcNumber(); + OrcNumber(std::string Orc_config_); + + ~OrcNumber(); + Number_Cfg num_cfg_; + + bool NumberOrc(model model); + }; +} // namespace Orc + + + + + + + +#endif \ No newline at end of file diff --git a/module/orc/orc_config.xml b/module/orc/orc_config.xml new file mode 100644 index 0000000..18e2006 --- /dev/null +++ b/module/orc/orc_config.xml @@ -0,0 +1,24 @@ + + + + +5 +255 +4 +255 +2 +255 + +666 +2 + + +1 + + diff --git a/opencv_onnx_inferring.hpp b/opencv_onnx_inferring.hpp new file mode 100644 index 0000000..89d5526 --- /dev/null +++ b/opencv_onnx_inferring.hpp @@ -0,0 +1,132 @@ +/* + * @name: opencv_onnx_inferring.hpp + * @namespace: ooi + * @class: model + * @brief: Load ONNX model and infer input image for classified int digit + * @author Unbinilium + * @version 1.0.1 + * @date 2021-05-10 + */ + +#ifndef _USE_NUMBER_ +#define _USE_NUMBER_ + +#pragma once_ +#include +using namespace std; + +#include + + +class model { + public: + /** + @brief: Init model from params + @param: onnx_model_path, the path of the modle on your machine, downloadable at https://github.com/onnx/models/blob/master/vision/classification/mnist/model/mnist-8.onnx + @param: input_size, define the input layer size, default to cv::Size(28, 28) + */ + inline model(const char* onnx_model_path, const cv::Size& input_size = cv::Size(28, 28)) { + model::load(onnx_model_path); + model::layers(); + + this->input_size = input_size; + } + model(){}; + ~model(){}; + /** + @brief: Inferring input image from loaded model, return classified int digit + @param: input, the image to classify (only 1 digit), const reference from cv::Mat + @param: median_blur_kernel_size, define the kernel size of median blur pre-processing, default to int 5, set 0 to disable + @param: hsv_lowerb, the lower range for hsv image, pixels inside the range equals to 1, otherwise equals to 0, default is the cv::Scalar() default + @param: hsv_upperb, the upper range for hsv image, pixels inside the range equals to 1, otherwise equals to 0, default is the cv::Scalar() default + @param: probability_threshold, the min probability of considerable probability to iterate, determined by the model, mnist-8.onnx has the output array from -1e5 to 1e5, default is 0 + @return: max_probability_idx, the most probable digit classified from input image in int type, -1 means all the probability is out of the threahold + */ + inline int inferring(const cv::Mat& hsv_input, const int median_blur_kernel_size = 5, const cv::Scalar& hsv_lowerb = cv::Scalar(), const cv::Scalar& hsv_upperb = cv::Scalar(), const float probability_threshold = 0) { + cv::resize(hsv_input, tmp, input_size); + if (median_blur_kernel_size != 0) { + cv::medianBlur(tmp, tmp, median_blur_kernel_size); + } + + cv::inRange(tmp, hsv_lowerb, hsv_upperb, tmp); + //开运算 + // cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT,cv::Size(3,3)); + // cv::morphologyEx(tmp, tmp, cv::MORPH_OPEN,element); + // cv::dilate(tmp,tmp,cv::Mat(cv::Size(3, 3), CV_8UC1)); + // cv::bitwise_not(tmp, tmp); + + cv::imshow("number_input_tmp", tmp); + + opencv_net.setInput(cv::dnn::blobFromImage(tmp)); + + float max_probability { 0 }; + int max_probability_idx { 0 }; + int i { -1 }; + opencv_net.forward().forEach([&probability_threshold, &max_probability, &max_probability_idx, &i](float &data, [[maybe_unused]] const int * position) -> void { + if (++i) { + if (data > max_probability) { + max_probability = data; + max_probability_idx = i; + } + } else { + if (data > probability_threshold) { + max_probability = data; + } else { + max_probability = probability_threshold; + max_probability_idx = -1; + } + } + }); + + return max_probability_idx; + } + + protected: + /* + @brief: Load model from onnx_model_path + @param: onnx_model_path, the path of the modle on your machine, downloadable at https://github.com/onnx/models/blob/master/vision/classification/mnist/model/mnist-8.onnx + */ + inline void load(const char* onnx_model_path) { + std::cout << "[OOI] opencv version: " << cv::getVersionString() << std::endl; + + model_path = onnx_model_path; + opencv_net = cv::dnn::readNetFromONNX(model_path); + + if (!opencv_net.empty()) { + std::cout << "[OOI] load model success: " << model_path << std::endl; + } else { + std::cout << "[OOI] load model failed: " << model_path << std::endl; + return; + } + +#if __has_include() + opencv_net.setPreferableBackend(cv::dnn::DNN_TARGET_CUDA); +#else + opencv_net.setPreferableBackend(cv::dnn::DNN_TARGET_CPU); +#endif + } + /* + @brief: Print model layers detail from loaded model + */ + inline void layers(void) { + if (opencv_net.empty()) { + std::cout << "[OOI] model is empty" << std::endl; + return; + } + + std::cout << "[OOI] model from " << model_path << " has layers: " << std::endl; + for (const auto& layer_name : opencv_net.getLayerNames()) { + std::cout << "\t\t" << layer_name << std::endl; + } + } + + private: + cv::dnn::Net opencv_net; + const char* model_path; + + cv::Size input_size; + cv::Mat tmp; + }; + + +#endif diff --git a/run.o b/run.o index f5b5b3f..9ba2685 100755 Binary files a/run.o and b/run.o differ