diff --git a/CMakeLists.txt b/CMakeLists.txt index 8325866..e19eb1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ PROJECT(SJTU-RM-CV) SET(CMAKE_CXX_STANDARD 11) -SET(CMAKE_BUILD_TYPE DEBUG) +SET(CMAKE_BUILD_TYPE RELEASE) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPATH=\"\\\"${PROJECT_SOURCE_DIR}\\\"\"") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${CMAKE_SYSTEM_NAME}") diff --git a/energy/include/energy/energy.h b/energy/include/energy/energy.h index a9e25f0..867a12c 100644 --- a/energy/include/energy/energy.h +++ b/energy/include/energy/energy.h @@ -66,6 +66,7 @@ private: int send_cnt;//向主控板发送的数据总次数 int camera_cnt;//摄像头数量 + int fans_cnt;//扇叶个数 int last_fans_cnt;//上一帧的扇叶个数 int guess_devide;//刚进入猜测状态时,猜测目标点在极坐标中的分区 int energy_rotation_direction;//风车旋转方向 @@ -80,11 +81,13 @@ private: float guess_polar_angle;//猜测的下一个目标装甲板极坐标角度 float last_base_angle;//上一帧的各扇叶在0区(0°~72°)的基础角度 float predict_rad;//预测提前角 + float predict_rad_norm;//预测提前角的绝对值 float attack_distance;//步兵与风车平面距离 float center_delta_yaw, center_delta_pitch;//对心时相差的角度 float yaw_rotation, pitch_rotation;//云台yaw轴和pitch轴应该转到的角度 float origin_yaw, origin_pitch;//初始的云台角度设定值 float shoot;//若为2,则要求主控板发弹 + float last_yaw, last_pitch;//PID中微分项 float sum_yaw, sum_pitch;//yaw和pitch的累计误差,即PID中积分项 systime time_start_guess; @@ -131,6 +134,7 @@ private: bool findFlowStrip(const cv::Mat src);//寻找图中的流动条 bool findCenterROI(const cv::Mat src);//框取中心R候选区 bool findFlowStripFan(const cv::Mat src);//寻找图中的流动条所在扇叶 + bool findFlowStripWeak(const cv::Mat src);//弱识别寻找图中的流动条 bool isValidFanContour(cv::Mat &src, const vector &fan_contour);//扇叶矩形尺寸要求 bool isValidArmorContour(const vector &armor_contour);//装甲板矩形尺寸要求 @@ -141,7 +145,9 @@ private: void showFans(std::string windows_name, const cv::Mat src);//显示扇叶 void showArmors(std::string windows_name, const cv::Mat src);//显示装甲板 void showBoth(std::string windows_name, const cv::Mat src);//显示扇叶和装甲板 + void showTarget(std::string windows_name, const cv::Mat src);//显示目标装甲板 void showCenterR(std::string windows_name, const cv::Mat src);//显示风车中心候选区R + void showFlowStrip(std::string windows_name, const cv::Mat src);//显示流动条 void showFlowStripFan(std::string windows_name, const cv::Mat src);//显示流动条所在扇叶 void showGuessTarget(std::string windows_name, const cv::Mat src);//显示猜测点位 diff --git a/energy/include/energy/param_struct_define.h b/energy/include/energy/param_struct_define.h index 8b2faf9..9e0fa7f 100644 --- a/energy/include/energy/param_struct_define.h +++ b/energy/include/energy/param_struct_define.h @@ -83,6 +83,9 @@ struct EnergyPartParam { long TARGET_CHANGE_DISTANCE_MAX;//目标未更改时,目标装甲板中心与原目标装甲板中心的距离变化最大值 long TWIN_POINT_MAX;//两个点相同时距离最大值 + + long STRIP_ARMOR_DISTANCE_MIN;//流动条中心和目标装甲板中心距离最小值 + long STRIP_ARMOR_DISTANCE_MAX;//流动条中心和目标装甲板中心距离最大值 }; diff --git a/energy/src/energy/clear/energy_init.cpp b/energy/src/energy/clear/energy_init.cpp index 1d11c6c..80caba9 100644 --- a/energy/src/energy/clear/energy_init.cpp +++ b/energy/src/energy/clear/energy_init.cpp @@ -30,6 +30,7 @@ void Energy::initEnergy() { send_cnt = 0; camera_cnt = 1; + fans_cnt = 0; last_fans_cnt = 0; guess_devide = 0; energy_rotation_direction = ANTICLOCKWISE; @@ -46,12 +47,15 @@ void Energy::initEnergy() { guess_polar_angle = -1000; last_base_angle = -1000; predict_rad = 25; + predict_rad_norm = 25; attack_distance = ATTACK_DISTANCE; center_delta_yaw = 1000; center_delta_pitch = 1000; yaw_rotation = 0; pitch_rotation = 0; shoot = 0; + last_yaw = 0; + last_pitch = 0; sum_yaw = 0; sum_pitch = 0; @@ -69,7 +73,6 @@ void Energy::initEnergy() { all_target_armor_centers.clear(); while(!recent_target_armor_centers.empty())recent_target_armor_centers.pop(); - } @@ -77,29 +80,29 @@ void Energy::initEnergy() { // 此函数对能量机关参数进行初始化 // --------------------------------------------------------------------------------------------------------------------- void Energy::initEnergyPartParam() { - gimbal_energy_part_param_.GRAY_THRESH = 120;//home +// gimbal_energy_part_param_.GRAY_THRESH = 120;//home // gimbal_energy_part_param_.GRAY_THRESH = 200;//official -// gimbal_energy_part_param_.GRAY_THRESH = 225; - gimbal_energy_part_param_.SPLIT_GRAY_THRESH = 230; + gimbal_energy_part_param_.GRAY_THRESH = 180;//game + gimbal_energy_part_param_.SPLIT_GRAY_THRESH = 180; gimbal_energy_part_param_.FAN_GRAY_THRESH = 75; gimbal_energy_part_param_.ARMOR_GRAY_THRESH = 80; - gimbal_energy_part_param_.FAN_CONTOUR_AREA_MAX = 6600; - gimbal_energy_part_param_.FAN_CONTOUR_AREA_MIN = 0; - gimbal_energy_part_param_.FAN_CONTOUR_LENGTH_MIN = 80; - gimbal_energy_part_param_.FAN_CONTOUR_LENGTH_MAX = 100; + gimbal_energy_part_param_.FAN_CONTOUR_AREA_MAX = 3000; + gimbal_energy_part_param_.FAN_CONTOUR_AREA_MIN = 500; + gimbal_energy_part_param_.FAN_CONTOUR_LENGTH_MIN = 55; + gimbal_energy_part_param_.FAN_CONTOUR_LENGTH_MAX = 95; gimbal_energy_part_param_.FAN_CONTOUR_WIDTH_MIN = 20; gimbal_energy_part_param_.FAN_CONTOUR_WIDTH_MAX = 52; - gimbal_energy_part_param_.FAN_CONTOUR_HW_RATIO_MAX = 4; - gimbal_energy_part_param_.FAN_CONTOUR_HW_RATIO_MIN = 1; - gimbal_energy_part_param_.FAN_CONTOUR_AREA_RATIO_MIN = 0.65; + gimbal_energy_part_param_.FAN_CONTOUR_HW_RATIO_MAX = 3.5; + gimbal_energy_part_param_.FAN_CONTOUR_HW_RATIO_MIN = 1.2; + gimbal_energy_part_param_.FAN_CONTOUR_AREA_RATIO_MIN = 0.6; gimbal_energy_part_param_.FAN_NON_ZERO_RATE_MAX = 0.8; gimbal_energy_part_param_.FAN_NON_ZERO_RATE_MIN = 0.48; // gimbal_energy_part_param_.FAN_NON_ZERO_RATE_MAX = 0.3; // gimbal_energy_part_param_.FAN_NON_ZERO_RATE_MIN = 0.16; - gimbal_energy_part_param_.ARMOR_CONTOUR_AREA_MAX = 100000; - gimbal_energy_part_param_.ARMOR_CONTOUR_AREA_MIN = 0; + gimbal_energy_part_param_.ARMOR_CONTOUR_AREA_MAX = 500; + gimbal_energy_part_param_.ARMOR_CONTOUR_AREA_MIN = 180; gimbal_energy_part_param_.ARMOR_CONTOUR_LENGTH_MIN = 16; gimbal_energy_part_param_.ARMOR_CONTOUR_LENGTH_MAX = 32; gimbal_energy_part_param_.ARMOR_CONTOUR_WIDTH_MIN = 5; @@ -107,42 +110,41 @@ void Energy::initEnergyPartParam() { gimbal_energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MAX = 3; gimbal_energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MIN = 1; - gimbal_energy_part_param_.CENTER_R_CONTOUR_AREA_MAX = 100000; - gimbal_energy_part_param_.CENTER_R_CONTOUR_AREA_MIN = 0; - gimbal_energy_part_param_.CENTER_R_CONTOUR_LENGTH_MIN = 8; - gimbal_energy_part_param_.CENTER_R_CONTOUR_LENGTH_MAX = 45; - gimbal_energy_part_param_.CENTER_R_CONTOUR_WIDTH_MIN = 8; - gimbal_energy_part_param_.CENTER_R_CONTOUR_WIDTH_MAX = 45; - gimbal_energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MAX = 3; + gimbal_energy_part_param_.CENTER_R_CONTOUR_AREA_MAX = 200; + gimbal_energy_part_param_.CENTER_R_CONTOUR_AREA_MIN = 40; + gimbal_energy_part_param_.CENTER_R_CONTOUR_LENGTH_MIN = 6; + gimbal_energy_part_param_.CENTER_R_CONTOUR_LENGTH_MAX = 20; + gimbal_energy_part_param_.CENTER_R_CONTOUR_WIDTH_MIN = 6; + gimbal_energy_part_param_.CENTER_R_CONTOUR_WIDTH_MAX = 20; + gimbal_energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MAX = 2; gimbal_energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MIN = 1; - gimbal_energy_part_param_.CENTER_R_CONTOUR_AREA_RATIO_MIN = 0.3; + gimbal_energy_part_param_.CENTER_R_CONTOUR_AREA_RATIO_MIN = 0.6; gimbal_energy_part_param_.CENTER_R_CONTOUR_INTERSETION_AREA_MIN = 10; - gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MAX = 3000; - gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MIN = 1000; + gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MAX = 2000; + gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MIN = 500; gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MIN = 60; gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MAX = 100; gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MIN = 20; gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MAX = 52; - gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MAX = 3; - gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MIN = 1; - gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MAX = 0.65; + gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MAX = 2.8; + gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MIN = 1.2; + gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MAX = 0.58; gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MIN = 0.34; - gimbal_energy_part_param_.FLOW_STRIP_FAN_NON_ZERO_RATE_MAX = 0.65; + gimbal_energy_part_param_.FLOW_STRIP_FAN_NON_ZERO_RATE_MAX = 0.58; gimbal_energy_part_param_.FLOW_STRIP_FAN_NON_ZERO_RATE_MIN = 0.34; // gimbal_energy_part_param_.FLOW_STRIP_FAN_NON_ZERO_RATE_MAX = 0.2; // gimbal_energy_part_param_.FLOW_STRIP_FAN_NON_ZERO_RATE_MIN = 0.08; - gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MAX = 100000; - gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MIN = 0; - gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MIN = 38; - gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MAX = 60; - gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MIN = 8; - gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX = 32; - gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MAX = 12; -// gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN = 4; - gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN = 1.8; - gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MIN = 0.5; + gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MAX = 700; + gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MIN = 100; + gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MIN = 32; + gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MAX = 55; + gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MIN = 4; + gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX = 20; + gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MAX = 7; + gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN = 3; + gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MIN = 0.6; gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_INTERSETION_AREA_MIN = 100; gimbal_energy_part_param_.TWIN_ANGEL_MAX = 10; @@ -151,6 +153,9 @@ void Energy::initEnergyPartParam() { gimbal_energy_part_param_.TARGET_CHANGE_DISTANCE_MAX = 20; gimbal_energy_part_param_.TWIN_POINT_MAX = 20; + gimbal_energy_part_param_.STRIP_ARMOR_DISTANCE_MIN = 28; + gimbal_energy_part_param_.STRIP_ARMOR_DISTANCE_MAX = 52; + chassis_energy_part_param_.GRAY_THRESH = 120;//home diff --git a/energy/src/energy/find/energy_finder.cpp b/energy/src/energy/find/energy_finder.cpp index e7e5e78..9827d7c 100644 --- a/energy/src/energy/find/energy_finder.cpp +++ b/energy/src/energy/find/energy_finder.cpp @@ -14,7 +14,7 @@ using std::vector; // 此函数用于寻找图像内所有的大风车扇叶 // --------------------------------------------------------------------------------------------------------------------- int Energy::findFans(const cv::Mat src) { - if (src.empty()){ + if (src.empty()) { if (show_info) cout << "empty!" << endl; return 0; } @@ -39,14 +39,13 @@ int Energy::findFans(const cv::Mat src) { // float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width; // float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width; // double cur_contour_area = contourArea(fan_contour); -// double non_zero_rate = nonZeroRateOfRotateRect(src_bin, cur_rect); -// if (length > 60 && width > 20) { -// fans.emplace_back(cv::minAreaRect(fan_contour)); -// cout << cur_rect.center << endl; -// cout << "fan area: " << length << '\t' << width << endl; -// cout << "non zero: " << nonZeroRateOfRotateRect(src_bin, cur_rect) << endl; -// cout << "rate: " << cur_contour_area / cur_size.area() << endl; -// } +// float length_width_ratio = length / width; +// cout << "area: " << cur_contour_area << '\t' << endl; +// cout << "length: " << length << '\t' << "width: " << width << '\t' << cur_rect.center << endl; +// cout << "HW: " << length_width_ratio << '\t' << cur_rect.center << endl; +// cout << "area ratio: " << cur_contour_area / cur_size.area() << '\t' << cur_rect.center << endl; +// cout< cur_size.width ? cur_size.height : cur_size.width; // float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width; -// if (length > 5 && width > 5) { -// armors.emplace_back(cv::minAreaRect(armor_contour)); -// cout << "armor area: " << length << '\t' << width << '\t' << cur_rect.center << endl; -// } +// double cur_contour_area = contourArea(armor_contour); +// float length_width_ratio = length / width; +// cout << "area: " << cur_contour_area << '\t' << endl; +// cout << "length: " << length << '\t' << "width: " << width << '\t' << cur_rect.center << endl; +// cout << "HW: " << length_width_ratio << '\t' << cur_rect.center << endl; +// cout << "area ratio: " << cur_contour_area / cur_size.area() << '\t' << cur_rect.center << endl; +// cout<(armors.size()); } @@ -120,7 +123,7 @@ int Energy::findArmors(const cv::Mat src) { // 此函数用于寻找图像内大风车中心字母“R” // --------------------------------------------------------------------------------------------------------------------- bool Energy::findCenterR(const cv::Mat src) { - if (src.empty()){ + if (src.empty()) { if (show_info) cout << "empty!" << endl; return false; } @@ -147,22 +150,18 @@ bool Energy::findCenterR(const cv::Mat src) { // Size2f cur_size = cur_rect.size; // float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width; // float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width; -// if (length < 10 || width < 5 || length>19) { -// continue; -// } -// std::vector intersection; -// if (rotatedRectangleIntersection(cur_rect, center_ROI, intersection) != 0 && -// contourArea(intersection) > energy_part_param_.CENTER_R_CONTOUR_INTERSETION_AREA_MIN) { -// centerR = cv::minAreaRect(center_R_contour); -// cout << "center R area: " << length << '\t' << width << '\t' << cur_rect.center << endl; -// cout << "R intersection: " << contourArea(intersection) << endl; -// return true; -// } -// cout << cur_rect.center << endl; +// double cur_contour_area = contourArea(center_R_contour); +// float length_width_ratio = length / width; +// cout << "area: " << cur_contour_area << '\t' << endl; +// cout << "length: " << length << '\t' << "width: " << width << '\t' << cur_rect.center << endl; +// cout << "HW: " << length_width_ratio << '\t' << cur_rect.center << endl; +// cout << "area ratio: " << cur_contour_area / cur_size.area() << '\t' << cur_rect.center << endl; +// cout< cur_size.width ? cur_size.height : cur_size.width; // float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width; // double cur_contour_area = contourArea(flow_strip_fan_contour); -// if (length > 40 && width > 30 && length < 110 && width < 100) { -// cout << cur_rect.center< intersection; RotatedRect cur_rect = minAreaRect(flow_strip_contour); + if (rotatedRectangleIntersection(cur_rect, candidate_flow_strip_fan, intersection) == 0) { continue; } else if (contourArea(intersection) > energy_part_param_.FLOW_STRIP_CONTOUR_INTERSETION_AREA_MIN) { flow_strips.emplace_back(cv::minAreaRect(flow_strip_contour)); // cout << "intersection: " << contourArea(intersection) << '\t' << cur_rect.center << endl; + } else { + continue; } -// RotatedRect cur_rect = minAreaRect(flow_strip_contour); -// Size2f cur_size = cur_rect.size; -// float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width; -// float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width; -// if (length / width > 2.5 && width > 7 && width<40) { -// cout << cur_rect.center << endl; -// flow_strip = cv::minAreaRect(flow_strip_contour); -// cout << "flow strip area: " << length << '\t' << width << endl; -// } -// cout << cur_rect.center << endl; +// Size2f cur_size = cur_rect.size; +// float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width; +// float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width; +// double cur_contour_area = contourArea(flow_strip_contour); +// float length_width_ratio = length / width; +// cout << "area: " << cur_contour_area << '\t' << endl; +// cout << "length: " << length << '\t' << "width: " << width << '\t' << cur_rect.center << endl; +// cout << "HW: " << length_width_ratio << '\t' << cur_rect.center << endl; +// cout << "area ratio: " << cur_contour_area / cur_size.area() << '\t' << cur_rect.center << endl; +// cout< candidate_armors = armors; + for (auto &candidate_armor: candidate_armors) { + Point2f vertices[4]; + candidate_armor.size.height *= 1.3; + candidate_armor.size.width *= 1.3; + candidate_armor.points(vertices); //计算矩形的4个顶点 + for (int i = 0; i < 4; i++) { + line(src_bin, vertices[i], vertices[(i + 1) % 4], Scalar(0, 0, 0), 20); + } + } + + cvtColor(src_bin, src_bin, CV_BGR2GRAY);//若读取三通道视频文件,需转换为单通道 + + FlowStripStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找 + if (show_process)imshow("weak struct", src_bin); +// waitKey(0); + + std::vector > flow_strip_contours; + findContours(src_bin, flow_strip_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); + + for (auto &flow_strip_contour : flow_strip_contours) { + if (!isValidFlowStripContour(flow_strip_contour)) { + continue; + } + + flow_strips.emplace_back(cv::minAreaRect(flow_strip_contour)); + +// RotatedRect cur_rect = minAreaRect(flow_strip_contour); +// Size2f cur_size = cur_rect.size; +// float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width; +// float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width; +// double cur_contour_area = contourArea(flow_strip_contour); +// float length_width_ratio = length / width; +// cout << "area: " << cur_contour_area << '\t' << endl; +// cout << "length: " << length << '\t' << "width: " << width << '\t' << cur_rect.center << endl; +// cout << "HW: " << length_width_ratio << '\t' << cur_rect.center << endl; +// cout << "area ratio: " << cur_contour_area / cur_size.area() << '\t' << cur_rect.center << endl; +// cout << endl; + + } +// cout << "size: " << flow_strips.size() << endl; + + if (flow_strips.empty()) { + if (show_info)cout << "weak flow strip false!" << endl; +// waitKey(0); + return false; + } else { + for (const auto &candidate_flow_strip: flow_strips) { + for (const auto &candidate_armor: armors) { + if (pointDistance(candidate_flow_strip.center, candidate_armor.center) < + energy_part_param_.STRIP_ARMOR_DISTANCE_MIN || + pointDistance(candidate_flow_strip.center, candidate_armor.center) > + energy_part_param_.STRIP_ARMOR_DISTANCE_MAX) { + continue; + } + float angle_armor = candidate_armor.size.width > candidate_armor.size.height ? candidate_armor.angle : + candidate_armor.angle - 90; + float angle_strip = candidate_flow_strip.size.width > candidate_flow_strip.size.height ? + candidate_flow_strip.angle: candidate_flow_strip.angle - 90; + + if (abs(angle_armor - angle_strip) < 60 || abs(angle_armor - angle_strip) > 120) { + continue; + } + target_armor = candidate_armor; + target_point = candidate_armor.center; + flow_strip = candidate_flow_strip; + return true; + } + } + if (show_info)cout << "weak flow strip false!" << endl; +// waitKey(0); + return false; + } +} + //---------------------------------------------------------------------------------------------------------------------- // 此函数用于框取中心R的寻找范围 // --------------------------------------------------------------------------------------------------------------------- diff --git a/energy/src/energy/get/predict_point_get.cpp b/energy/src/energy/get/predict_point_get.cpp index 53704ff..4550b29 100644 --- a/energy/src/energy/get/predict_point_get.cpp +++ b/energy/src/energy/get/predict_point_get.cpp @@ -16,8 +16,9 @@ using std::vector; // --------------------------------------------------------------------------------------------------------------------- void Energy::getPredictPoint(cv::Point target_point) { if (is_big) { - if (energy_rotation_direction == 1) rotate(target_point); - if (energy_rotation_direction == -1) rotate(target_point); + if (energy_rotation_direction == 1) predict_rad = predict_rad_norm; + else if (energy_rotation_direction == -1) predict_rad = -predict_rad_norm; + rotate(target_point); } else if (is_small) predict_point = target_point; } diff --git a/energy/src/energy/judge/judge_contour.cpp b/energy/src/energy/judge/judge_contour.cpp index 69f03c7..6f43747 100644 --- a/energy/src/energy/judge/judge_contour.cpp +++ b/energy/src/energy/judge/judge_contour.cpp @@ -100,8 +100,8 @@ bool Energy::isValidArmorContour(const vector &armor_contour) { // --------------------------------------------------------------------------------------------------------------------- bool Energy::isValidCenterRContour(const vector ¢er_R_contour) { double cur_contour_area = contourArea(center_R_contour); - if (cur_contour_area > energy_part_param_.ARMOR_CONTOUR_AREA_MAX || - cur_contour_area < energy_part_param_.ARMOR_CONTOUR_AREA_MIN) { + if (cur_contour_area > energy_part_param_.CENTER_R_CONTOUR_AREA_MAX || + cur_contour_area < energy_part_param_.CENTER_R_CONTOUR_AREA_MIN) { //cout< &flow_strip_contour length > energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MAX || width > energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX) { // cout<<"length width fail."<30)cout << "length: " << length << '\t' << "width: " << width << '\t' << cur_rect.center << endl; return false; //矩形边长不合适 } @@ -225,12 +225,12 @@ bool Energy::isValidFlowStripContour(const vector &flow_strip_contour if (length_width_ratio > energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MAX || length_width_ratio < energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN) { // cout<<"hw fail."<3.5)cout << "HW: " << length_width_ratio << '\t' << cur_rect.center << endl; return false; //长宽比不合适 } if (cur_contour_area / cur_size.area() < energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MIN) { -// cout << "area ratio: " << cur_contour_area / cur_size.area() << '\t' << cur_rect.center << endl; +// if(cur_contour_area / cur_size.area()>0.5)cout << "area ratio: " << cur_contour_area / cur_size.area() << '\t' << cur_rect.center << endl; return false;//轮廓对矩形的面积占有率不合适 } return true; diff --git a/energy/src/energy/mark/mark.cpp b/energy/src/energy/mark/mark.cpp index 264ac59..bdf6c03 100644 --- a/energy/src/energy/mark/mark.cpp +++ b/energy/src/energy/mark/mark.cpp @@ -12,7 +12,7 @@ using namespace cv; // 此函数用于记录操作手的微调dx和dy // --------------------------------------------------------------------------------------------------------------------- void Energy::writeDownSlightChange(cv::Mat &src) { - if (findFans(src) >= 4) { + if (fans_cnt >= 4) { FILE *fp_delta = fopen(PROJECT_DIR"/Mark/delta.txt", "w"); if (fp_delta) { fprintf(fp_delta, "delta_x: %d, delta_y: %d\n", mcu_data.delta_x + manual_delta_x, diff --git a/energy/src/energy/run.cpp b/energy/src/energy/run.cpp index 85a90c6..9cf3006 100644 --- a/energy/src/energy/run.cpp +++ b/energy/src/energy/run.cpp @@ -78,13 +78,19 @@ void Energy::runBig(cv::Mat &gimbal_src) { if (show_process)imshow("bin", gimbal_src); if (findArmors(gimbal_src) < 1)return; if (show_energy)showArmors("armor", gimbal_src); - if (!findFlowStripFan(gimbal_src))return; - if (!findTargetInFlowStripFan()) return; - if (!findFlowStrip(gimbal_src))return; + if (!findFlowStripFan(gimbal_src)) { + if (!findFlowStripWeak(gimbal_src))return; + } else { + if (show_energy)showFlowStripFan("strip fan", gimbal_src); + if (!findTargetInFlowStripFan()) return; + if (!findFlowStrip(gimbal_src))return; + } if (!findCenterROI(gimbal_src))return; - if (show_energy)showFlowStripFan("strip", gimbal_src); + if (show_energy)showFlowStrip("strip", gimbal_src); if (!findCenterR(gimbal_src))return; if (show_energy)showCenterR("R", gimbal_src); + fans_cnt = findFans(gimbal_src); + if (show_energy)showFans("fans", gimbal_src); // getCenter(); // sendEnergy(); @@ -92,6 +98,7 @@ void Energy::runBig(cv::Mat &gimbal_src) { changeTarget(); getTargetPolarAngle(); + if (energy_rotation_init) { initRotation(); return; @@ -115,9 +122,16 @@ void Energy::runSmall(cv::Mat &gimbal_src) { if (show_process)imshow("bin", gimbal_src); if (findArmors(gimbal_src) < 1)return; if (show_energy)showArmors("armor", gimbal_src); - if (!findFlowStripFan(gimbal_src))return; - if (!findTargetInFlowStripFan()) return; - if (!findFlowStrip(gimbal_src))return; + if (!findFlowStripFan(gimbal_src)) { + if (!findFlowStripWeak(gimbal_src))return; + } else { + if (show_energy)showFlowStripFan("strip fan", gimbal_src); + if (!findTargetInFlowStripFan()) return; + if (!findFlowStrip(gimbal_src))return; + } + if (show_energy)showTarget("target", gimbal_src); + fans_cnt = findFans(gimbal_src); + if (show_energy)showFans("fans", gimbal_src); // getCenter(); // sendEnergy(); diff --git a/energy/src/energy/send/send.cpp b/energy/src/energy/send/send.cpp index 04fd7fd..c140ae8 100644 --- a/energy/src/energy/send/send.cpp +++ b/energy/src/energy/send/send.cpp @@ -8,6 +8,7 @@ using namespace std; +#define MINMAX(value, min, max) value = ((value) < (min)) ? (min) : ((value) > (max) ? (max) : (value)) //---------------------------------------------------------------------------------------------------------------------- // 此函数用于发送能量机关数据 @@ -17,21 +18,34 @@ void Energy::sendEnergy() { if (camera_cnt == 1) { sum_yaw += yaw_rotation; sum_pitch += pitch_rotation; - yaw_rotation = AIM_KP * yaw_rotation + AIM_KI * sum_yaw; - pitch_rotation = AIM_KP * pitch_rotation + AIM_KI * sum_pitch; + MINMAX(sum_yaw, -100, 100); + MINMAX(sum_pitch, -100, 100);\ + yaw_rotation = BIG_YAW_AIM_KP * yaw_rotation + BIG_YAW_AIM_KI * sum_yaw + BIG_YAW_AIM_KD * (yaw_rotation - last_yaw); + pitch_rotation = BIG_PITCH_AIM_KP * pitch_rotation + BIG_PITCH_AIM_KI * sum_pitch + + BIG_PITCH_AIM_KD * (pitch_rotation - last_pitch); } else if (is_chassis) { - sum_yaw += yaw_rotation - mcu_data.curr_yaw; - sum_pitch += pitch_rotation - mcu_data.curr_pitch; - yaw_rotation = AIM_KP * (yaw_rotation - mcu_data.curr_yaw) + AIM_KI * sum_yaw; - pitch_rotation = AIM_KP * (pitch_rotation - mcu_data.curr_pitch) + AIM_KI * sum_pitch; + sum_yaw += yaw_rotation - mcuData.curr_yaw; + sum_pitch += pitch_rotation - mcuData.curr_pitch; + yaw_rotation = BIG_YAW_AIM_KP * (yaw_rotation - mcuData.curr_yaw) + BIG_YAW_AIM_KI * sum_yaw; + pitch_rotation = BIG_PITCH_AIM_KP * (pitch_rotation - mcuData.curr_pitch) + BIG_PITCH_AIM_KI * sum_pitch; } + } else if (is_small){ + sum_yaw += yaw_rotation; + sum_pitch += pitch_rotation; + MINMAX(sum_yaw, -100, 100); + MINMAX(sum_pitch, -100, 100); + yaw_rotation = SMALL_YAW_AIM_KP * yaw_rotation + SMALL_YAW_AIM_KD * (yaw_rotation - last_yaw); + pitch_rotation = SMALL_PITCH_AIM_KP * pitch_rotation + SMALL_PITCH_AIM_KD * (pitch_rotation - last_pitch); } + if (change_target) { sendTarget(serial, yaw_rotation, pitch_rotation, 5, 0); } else if (is_guessing) { sendTarget(serial, yaw_rotation, pitch_rotation, 6, 0); - } else { + } /*else if (fans_cnt >= 4) { + sendTarget(serial, yaw_rotation, pitch_rotation, 7, 0); + }*/ else { sendTarget(serial, yaw_rotation, pitch_rotation, shoot, 0); } @@ -51,7 +65,7 @@ void Energy::sendTarget(Serial &serial, float x, float y, float z) { time_t t = time(nullptr); if (last_time != t) { last_time = t; - cout << "Energy: fps:" << fps << ", (" << x << "," << y << "," << z << ")" << endl; + cout << "Energy: fps:" << fps << ", (" << x << "," << y << "," << z << ")" << endl; fps = 0; } fps += 1; diff --git a/energy/src/energy/show/show.cpp b/energy/src/energy/show/show.cpp index 0455ffa..23a8205 100644 --- a/energy/src/energy/show/show.cpp +++ b/energy/src/energy/show/show.cpp @@ -98,6 +98,32 @@ void Energy::showBoth(std::string windows_name, const cv::Mat src) { } +//---------------------------------------------------------------------------------------------------------------------- +// 此函数用于显示图像中目标装甲板 +// --------------------------------------------------------------------------------------------------------------------- +void Energy::showTarget(std::string windows_name, const cv::Mat src) { + if (src.empty())return; + static Mat image2show; + + if (src.type() == CV_8UC1) // 黑白图像 + { + cvtColor(src, image2show, COLOR_GRAY2RGB); + + } else if (src.type() == CV_8UC3) //RGB 彩色 + { + image2show = src.clone(); + } + for (const auto &armor : armors) { + if (pointDistance(armor.center, target_point) < energy_part_param_.TWIN_POINT_MAX) { + Point2f vertices[4]; //定义矩形的4个顶点 + armor.points(vertices); //计算矩形的4个顶点 + for (int i = 0; i < 4; i++) + line(image2show, vertices[i], vertices[(i + 1) % 4], Scalar(255, 255, 0), 2); + } + } + imshow(windows_name, image2show); +} + //---------------------------------------------------------------------------------------------------------------------- // 此函数用于显示图像中所有可能的风车中心候选区R // --------------------------------------------------------------------------------------------------------------------- @@ -126,7 +152,7 @@ void Energy::showCenterR(std::string windows_name, const cv::Mat src) { //---------------------------------------------------------------------------------------------------------------------- -// 此函数用于显示图像中所有流动条 +// 此函数用于显示图像中流动条扇叶 // --------------------------------------------------------------------------------------------------------------------- void Energy::showFlowStripFan(std::string windows_name, const cv::Mat src) { if (src.empty())return; @@ -145,7 +171,23 @@ void Energy::showFlowStripFan(std::string windows_name, const cv::Mat src) { flow_strip_fan.points(strip_fan_vertices); //计算矩形的4个顶点for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++) line(image2show, strip_fan_vertices[i], strip_fan_vertices[(i + 1) % 4], Scalar(127, 127, 255), 2); +} +//---------------------------------------------------------------------------------------------------------------------- +// 此函数用于显示图像中流动条扇叶 +// --------------------------------------------------------------------------------------------------------------------- +void Energy::showFlowStrip(std::string windows_name, const cv::Mat src) { + if (src.empty())return; + static Mat image2show; + + if (src.type() == CV_8UC1) // 黑白图像 + { + cvtColor(src, image2show, COLOR_GRAY2RGB); + + } else if (src.type() == CV_8UC3) //RGB 彩色 + { + image2show = src.clone(); + } Point2f strip_vertices[4]; //定义矩形的4个顶点 flow_strip.points(strip_vertices); //计算矩形的4个顶点 diff --git a/others/include/config/setconfig.h b/others/include/config/setconfig.h index e23db56..7a7c34e 100644 --- a/others/include/config/setconfig.h +++ b/others/include/config/setconfig.h @@ -29,13 +29,37 @@ #define ARMOR_CAMERA_GAIN (30) #endif #ifndef ENERGY_CAMERA_GAIN - #define ENERGY_CAMERA_GAIN (30) + #define ENERGY_CAMERA_GAIN (20) #endif -#ifndef AIM_KP - #define AIM_KP (6) +#ifndef SMALL_YAW_AIM_KD + #define SMALL_YAW_AIM_KD (1.5) #endif -#ifndef AIM_KI - #define AIM_KI (0.1) +#ifndef SMALL_YAW_AIM_KP + #define SMALL_YAW_AIM_KP (2.5) +#endif +#ifndef SMALL_PITCH_AIM_KD + #define SMALL_PITCH_AIM_KD (1.3) +#endif +#ifndef SMALL_PITCH_AIM_KP + #define SMALL_PITCH_AIM_KP (2.4) +#endif +#ifndef BIG_YAW_AIM_KD + #define BIG_YAW_AIM_KD (1) +#endif +#ifndef BIG_YAW_AIM_KP + #define BIG_YAW_AIM_KP (5.5) +#endif +#ifndef BIG_YAW_AIM_KI + #define BIG_YAW_AIM_KI (0.1) +#endif +#ifndef BIG_PITCH_AIM_KD + #define BIG_PITCH_AIM_KD (1) +#endif +#ifndef BIG_PITCH_AIM_KP + #define BIG_PITCH_AIM_KP (5.5) +#endif +#ifndef BIG_PITCH_AIM_KI + #define BIG_PITCH_AIM_KI (0.1) #endif #ifndef COMPENSATE_YAW #define COMPENSATE_YAW (5)