diff --git a/CMakeLists.txt b/CMakeLists.txt index a465f8d..efd23a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ PROJECT(SJTU-RM-CV) SET(CMAKE_CXX_STANDARD 11) -SET(CMAKE_BUILD_TYPE RELEASE) +SET(CMAKE_BUILD_TYPE DEBUG) 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 9eb8193..8b30574 100644 --- a/energy/include/energy/energy.h +++ b/energy/include/energy/energy.h @@ -42,10 +42,12 @@ private: int fans_cnt;//图像中的扇叶个数 int armors_cnt;//图像中的装甲板个数 int centerRs_cnt;//图像中可能的风车中心字母R选区个数 + int flow_strip_fans_cnt;//图像中的含流动条扇叶个数 int flow_strips_cnt;//图像中的流动条个数 int last_fans_cnt;//上一帧的扇叶个数 int last_armors_cnt;//上一帧的装甲板个数 - int last_flow_strips_cnt;// + int last_flow_strip_fans_cnt;//上一帧的含流动条扇叶个数 + int last_flow_strips_cnt;//上一帧的流动条个数 int gimble_cnt; //经过的帧数 double radius;//大风车半径 float target_polar_angle;//待击打装甲板的极坐标角度 @@ -71,6 +73,9 @@ private: std::vector armors;//图像中所有装甲板 std::vector centerRs;//风车中心字母R的可能候选区 std::vector flow_strips;//图像中所有流动条(理论上只有一个) + std::vector flow_strip_fans;//图像中所有流动条所在扇叶(理论上只有一个) + std::vector center_ROI;//风车中心候选区 + std::vector target_armor;//目标装甲板(理论上仅一个) cv::Point circle_center_point;//风车圆心坐标 cv::Point target_point;//目标装甲板中心坐标 @@ -89,18 +94,21 @@ private: int findFan(const cv::Mat src, int &last_fans_cnt);//寻找图中所有扇叶 int findArmor(const cv::Mat src, int &last_armors_cnt);//寻找图中所有装甲板 int findCenterR(const cv::Mat src);//寻找图中可能的风车中心字母R - int findFlowStrip(const cv::Mat src, int &last_flow_strips_cnt);//寻找图中所有流动条 + int findFlowStrip(const cv::Mat src, int &last_flow_strips_cnt);//寻找图中的流动条 + void findCenterROI(const cv::Mat src);//框取中心R候选区 + int findFlowStripFan(const cv::Mat src, int &last_flow_strip_fans_cnt);//寻找图中的流动条所在扇叶 - bool isValidFanContour(const vector fan_contour);//扇叶矩形尺寸要求 - bool isValidArmorContour(const vector armor_contour);//装甲板矩形尺寸要求 - bool isValidCenterRContour(const vector center_R_contour);//风车中心选区尺寸要求 - bool isValidFlowStripContour(const vector flow_strip_contour);//流动条矩形尺寸要求 + bool isValidFanContour(const vector &fan_contour);//扇叶矩形尺寸要求 + bool isValidArmorContour(const vector &armor_contour);//装甲板矩形尺寸要求 + bool isValidCenterRContour(const vector ¢er_R_contour);//风车中心选区尺寸要求 + bool isValidFlowStripContour(const vector &flow_strip_contour);//流动条扇叶矩形尺寸要求 + bool isValidFlowStripFanContour(const vector &flow_strip_fan_contour);//流动条扇叶矩形尺寸要求 void showFanContours(std::string windows_name, const cv::Mat src);//显示扇叶 void showArmorContours(std::string windows_name, const cv::Mat src);//显示装甲板 void showBothContours(std::string windows_name, const cv::Mat src);//显示扇叶和装甲板 void showCenterRContours(std::string windows_name, const cv::Mat src);//显示风车中心候选区R - void showFlowStripContours(std::string windows_name, const cv::Mat src);//显示流动条 + void showFlowStripFanContours(std::string windows_name, const cv::Mat src);//显示流动条所在扇叶 void getFanPolarAngle();//获取扇叶极坐标角度 void getArmorPolarAngle();//获取装甲板极坐标角度 @@ -110,7 +118,7 @@ private: void findTargetByPolar();//通过极坐标角度匹配获取目标装甲板的极坐标角度和装甲板中心坐标 void findTargetByIntersection();//通过面积重合度匹配获取目标装甲板的极坐标角度和装甲板中心坐标 - bool findTargetInFlowStrip();//在已发现的流动条区域中寻找待击打装甲板 + bool findTargetInFlowStripFan();//在已发现的流动条区域中寻找待击打装甲板 void rotate();//获取预测点位 void stretch(cv::Point point_1, cv::Point2f &point_2);//将像素差转换为实际距离差 diff --git a/energy/include/energy/param_struct_define.h b/energy/include/energy/param_struct_define.h index b660780..1062c75 100644 --- a/energy/include/energy/param_struct_define.h +++ b/energy/include/energy/param_struct_define.h @@ -24,6 +24,8 @@ struct EnergyPart { rect = cv::minAreaRect(c); angle = cv::minAreaRect(c).angle; }; + + EnergyPart(cv::RotatedRect rect=cv::RotatedRect(), float angle=0, vector contour=vector()):rect(rect),angle(angle),contour(contour){}; }; @@ -66,17 +68,29 @@ struct EnergyPartParam { float CENTER_R_CONTOUR_HW_RATIO_MAX;//风车中心R长宽比最大值 float CENTER_R_CONTOUR_HW_RATIO_MIN;//风车中心R长宽比最小值 float CENTER_R_CONTOUR_AREA_RATIO_MIN;//装甲板轮廓占旋转矩形面积比最小值 + float CENTER_R_CONTOUR_INTERSETION_AREA_MIN;//中心R占ROI区的面积最小值 + + long FLOW_STRIP_FAN_CONTOUR_AREA_MAX;//流动条扇叶(待击打)面积最大值 + long FLOW_STRIP_FAN_CONTOUR_AREA_MIN;//流动条扇叶(待击打)面积最小值 + long FLOW_STRIP_FAN_CONTOUR_LENGTH_MIN;//流动条扇叶(待击打)长边长度最小值 + long FLOW_STRIP_FAN_CONTOUR_WIDTH_MIN;//流动条扇叶(待击打)宽边长度最小值 + long FLOW_STRIP_FAN_CONTOUR_LENGTH_MAX;//流动条扇叶(待击打)长边长度最大值 + long FLOW_STRIP_FAN_CONTOUR_WIDTH_MAX;//流动条扇叶(待击打)宽边长度最大值 + float FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MAX;//流动条扇叶(待击打)长宽比最大值 + float FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MIN;//流动条扇叶(待击打)长宽比最小值 + float FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MAX;//装甲板轮廓占旋转矩形面积比最小值 + float FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MIN;//装甲板轮廓占旋转矩形面积比最小值 long FLOW_STRIP_CONTOUR_AREA_MAX;//流动条(待击打)面积最大值 long FLOW_STRIP_CONTOUR_AREA_MIN;//流动条(待击打)面积最小值 long FLOW_STRIP_CONTOUR_LENGTH_MIN;//流动条(待击打)长边长度最小值 - long FLOW_STRIP_CONTOUR_WIDTH_MIN;//流动条(待击打)长边长度最大值 - long FLOW_STRIP_CONTOUR_LENGTH_MAX;//流动条(待击打)宽边长度最小值 + long FLOW_STRIP_CONTOUR_WIDTH_MIN;//流动条(待击打)宽边长度最小值 + long FLOW_STRIP_CONTOUR_LENGTH_MAX;//流动条(待击打)长边长度最大值 long FLOW_STRIP_CONTOUR_WIDTH_MAX;//流动条(待击打)宽边长度最大值 float FLOW_STRIP_CONTOUR_HW_RATIO_MAX;//流动条(待击打)长宽比最大值 float FLOW_STRIP_CONTOUR_HW_RATIO_MIN;//流动条(待击打)长宽比最小值 - float FLOW_STRIP_CONTOUR_AREA_RATIO_MAX;//装甲板轮廓占旋转矩形面积比最小值 float FLOW_STRIP_CONTOUR_AREA_RATIO_MIN;//装甲板轮廓占旋转矩形面积比最小值 + float FLOW_STRIP_CONTOUR_INTERSETION_AREA_MIN;//流动条占旋转矩形面积比最小值 float TWIN_ANGEL_MAX;//扇叶和装甲板匹配时极坐标角度差的最大值 long INTERSETION_CONTOUR_AREA_MIN;//扇叶与装甲板匹配时的最小重合面积 diff --git a/energy/src/energy/energy_init.cpp b/energy/src/energy/energy_init.cpp index 10e1859..ea01939 100644 --- a/energy/src/energy/energy_init.cpp +++ b/energy/src/energy/energy_init.cpp @@ -21,6 +21,7 @@ void Energy::initEnergy() { armors_cnt = 0; centerRs_cnt = 0; flow_strips_cnt = 0; + flow_strip_fans_cnt = 0; gimble_cnt = 0; circle_center_point = Point(0, 0); target_point = Point(0, 0); @@ -35,6 +36,7 @@ void Energy::initEnergy() { last_fans_cnt = 0; last_armors_cnt = 0; last_flow_strips_cnt = 0; + last_flow_strip_fans_cnt = 0; send_cnt = 0; yaw_rotation = 0; pitch_rotation = 0; @@ -54,6 +56,9 @@ void Energy::initEnergy() { armors.clear(); centerRs.clear(); flow_strips.clear(); + flow_strip_fans.clear(); + center_ROI.clear(); + target_armor.clear(); fan_polar_angle.clear(); armor_polar_angle.clear(); @@ -122,17 +127,29 @@ void Energy::initEnergyPartParam() { energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MAX = 3; energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MIN = 1; energy_part_param_.CENTER_R_CONTOUR_AREA_RATIO_MIN = 0.7; + energy_part_param_.CENTER_R_CONTOUR_INTERSETION_AREA_MIN = 10; - energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MAX = 17000; + energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MAX = 17000; + energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MIN = 0; + energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MIN = 90; + energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MIN = 35; + energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MAX = 140; + energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MAX = 60; + energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MAX = 3; + energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MIN = 1; + energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MAX = 0.55; + energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MIN = 0.25; + + energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MAX = 100000; energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MIN = 0; - energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MIN = 90; - energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MIN = 35; - energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MAX = 140; - energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX = 60; - energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MAX = 3; - energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN = 1; - energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MAX = 0.55; - energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MIN = 0.25; + energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MIN = 50; + energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MIN = 3; + energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MAX = 90; + energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX = 20; + energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MAX = 12; + energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN = 4; + energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MIN = 0.5; + energy_part_param_.FLOW_STRIP_CONTOUR_INTERSETION_AREA_MIN = 300; energy_part_param_.TWIN_ANGEL_MAX = 10; energy_part_param_.INTERSETION_CONTOUR_AREA_MIN = 60; diff --git a/energy/src/energy/find/energy_finder.cpp b/energy/src/energy/find/energy_finder.cpp index 868a817..a5bc814 100644 --- a/energy/src/energy/find/energy_finder.cpp +++ b/energy/src/energy/find/energy_finder.cpp @@ -9,7 +9,6 @@ using std::endl; using std::vector; - //---------------------------------------------------------------------------------------------------------------------- // 此函数用于寻找图像内所有的大风车扇叶 // --------------------------------------------------------------------------------------------------------------------- @@ -18,18 +17,18 @@ int Energy::findFan(const cv::Mat src, int &last_fans_cnt) { static Mat src_bin; src_bin = src.clone(); // threshold(src, src_bin, energy_part_param_.FAN_GRAY_THRESH, 255, THRESH_BINARY); - if(src.type() == CV_8UC3){ + if (src.type() == CV_8UC3) { cvtColor(src_bin, src_bin, CV_BGR2GRAY);//若读取三通道视频文件,需转换为单通道 } - std::vector > fan_contours; - StructingElementClose(src_bin,6,6);//图像膨胀,防止图像断开并更方便寻找 + std::vector > fan_contours; + StructingElementClose(src_bin, 6, 6);//图像膨胀,防止图像断开并更方便寻找 // imshow("fan struct",src_bin); - findContours(src_bin, fan_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); + findContours(src_bin, fan_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); - for (auto &fan_contour : fan_contours) { - if (!isValidFanContour(fan_contour)) { - continue; - } + for (auto &fan_contour : fan_contours) { + if (!isValidFanContour(fan_contour)) { + continue; + } fans.emplace_back(fan_contour); // RotatedRect cur_rect = minAreaRect(fan_contour); @@ -41,46 +40,42 @@ int Energy::findFan(const cv::Mat src, int &last_fans_cnt) { // fans.emplace_back(fan_contour); // cout<<"fan area: "<(fans.size()); - return -1;//寻找到的扇叶比上一帧少,说明该帧有误,返回-1 - } - last_fans_cnt = static_cast(fans.size()); - return static_cast(fans.size()); + } + if (fans.size() < last_fans_cnt) { + last_fans_cnt = static_cast(fans.size()); + return -1;//寻找到的扇叶比上一帧少,说明该帧有误,返回-1 + } + last_fans_cnt = static_cast(fans.size()); + return static_cast(fans.size()); } - - //---------------------------------------------------------------------------------------------------------------------- // 此函数用于寻找图像内所有的大风车装甲板模块 // --------------------------------------------------------------------------------------------------------------------- int Energy::findArmor(const cv::Mat src, int &last_armors_cnt) { - if (src.empty())return 0; + if (src.empty())return 0; static Mat src_bin; src_bin = src.clone(); // threshold(src, src_bin, energy_part_param_.ARMOR_GRAY_THRESH, 255, THRESH_BINARY); - if(src.type() == CV_8UC3){ + if (src.type() == CV_8UC3) { cvtColor(src_bin, src_bin, CV_BGR2GRAY);//若读取三通道视频文件,需转换为单通道 } - std::vector > armor_contours; + std::vector > armor_contours; std::vector > armor_contours_external;//用总轮廓减去外轮廓,只保留内轮廓,除去流动条的影响。 StructingElementErodeDilate(src_bin);//图像膨胀,防止图像断开并更方便寻找 - imshow("armor struct",src_bin); + imshow("armor struct", src_bin); - findContours(src_bin, armor_contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE); + findContours(src_bin, armor_contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE); findContours(src_bin, armor_contours_external, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); for (int i = 0; i < armor_contours_external.size(); i++)//去除外轮廓 { unsigned long external_contour_size = armor_contours_external[i].size(); - for (int j = 0; j < armor_contours.size(); j++) - { + for (int j = 0; j < armor_contours.size(); j++) { unsigned long all_size = armor_contours[j].size(); - if (external_contour_size == all_size) - { + if (external_contour_size == all_size) { swap(armor_contours[j], armor_contours[armor_contours.size() - 1]); armor_contours.pop_back(); break; @@ -88,10 +83,9 @@ int Energy::findArmor(const cv::Mat src, int &last_armors_cnt) { } } for (auto &armor_contour : armor_contours) { - if (!isValidArmorContour(armor_contour)) - { - continue; - } + if (!isValidArmorContour(armor_contour)) { + continue; + } armors.emplace_back(armor_contour); // RotatedRect cur_rect = minAreaRect(armor_contour); @@ -103,19 +97,16 @@ int Energy::findArmor(const cv::Mat src, int &last_armors_cnt) { // cout<<"armor area: "<(armors.size()); - return -1;//寻找到的装甲板比上一帧少,说明该帧有误,返回-1 - } - last_armors_cnt = static_cast(armors.size()); - return static_cast(armors.size()); + } + if (armors.size() < last_armors_cnt) { + last_armors_cnt = static_cast(armors.size()); + return -1;//寻找到的装甲板比上一帧少,说明该帧有误,返回-1 + } + last_armors_cnt = static_cast(armors.size()); + return static_cast(armors.size()); } - - - //---------------------------------------------------------------------------------------------------------------------- // 此函数用于寻找图像内大风车中心字母“R” // --------------------------------------------------------------------------------------------------------------------- @@ -124,54 +115,93 @@ int Energy::findCenterR(const cv::Mat src) { static Mat src_bin; src_bin = src.clone(); // threshold(src, src_bin, energy_part_param_.ARMOR_GRAY_THRESH, 255, THRESH_BINARY); - if(src.type() == CV_8UC3){ + if (src.type() == CV_8UC3) { cvtColor(src_bin, src_bin, CV_BGR2GRAY); } std::vector > center_R_contours; StructingElementErodeDilate(src_bin); // imshow("R struct",src_bin); findContours(src_bin, center_R_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); - for (auto ¢er_R_contour : center_R_contours) { - if (!isValidCenterRContour(center_R_contour)) - { + if (!isValidCenterRContour(center_R_contour)) { continue; } centerRs.emplace_back(center_R_contour); - /*RotatedRect cur_rect = minAreaRect(center_R_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>10 && width>5){ - centerRs.emplace_back(center_R_contour); - cout<<"center R area: "< 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){ +// centerRs.emplace_back(center_R_contour); +// cout<<"center R area: "<(centerRs.size()); } - //---------------------------------------------------------------------------------------------------------------------- -// 此函数用于判断找到的矩形候选区是否为扇叶 +// 此函数用于判断找到的矩形候选区是否为含流动条的扇叶 // --------------------------------------------------------------------------------------------------------------------- - -int Energy::findFlowStrip(const cv::Mat src, int &last_flow_strips_cnt){ +int Energy::findFlowStripFan(const cv::Mat src, int &last_flow_strip_fans_cnt) { if (src.empty())return 0; static Mat src_bin; src_bin = src.clone(); // threshold(src, src_bin, energy_part_param_.FAN_GRAY_THRESH, 255, THRESH_BINARY); - if(src.type() == CV_8UC3){ + if (src.type() == CV_8UC3) { cvtColor(src_bin, src_bin, CV_BGR2GRAY);//若读取三通道视频文件,需转换为单通道 } - std::vector > flow_strip_contours; - StructingElementClose(src_bin,6,6);//图像膨胀,防止图像断开并更方便寻找 - imshow("flow_strip struct",src_bin); + std::vector > flow_strip_fan_contours; + StructingElementClose(src_bin, 6, 6);//图像膨胀,防止图像断开并更方便寻找 +// imshow("flow strip fan struct", src_bin); + findContours(src_bin, flow_strip_fan_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); + + for (auto &flow_strip_fan_contour : flow_strip_fan_contours) { + if (!isValidFlowStripFanContour(flow_strip_fan_contour)) { + continue; + } + + flow_strip_fans.emplace_back(flow_strip_fan_contour); + +// RotatedRect cur_rect = minAreaRect(flow_strip_fan_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>20&&width>20){ +// cout<(flow_strip_fans.size()); + return -1;//寻找到的流动条扇叶比上一帧少,说明该帧有误,返回-1 + } + last_flow_strip_fans_cnt = static_cast(flow_strip_fans.size()); + return static_cast(flow_strip_fans.size()); +} + + +//---------------------------------------------------------------------------------------------------------------------- +// 此函数用于寻找流动条 +// --------------------------------------------------------------------------------------------------------------------- +int Energy::findFlowStrip(const cv::Mat src, int &last_flow_strips_cnt) { + + if (src.empty())return 0; + cv::Mat src_bin; + src_bin = src.clone(); + if (src.type() == CV_8UC3) { + cvtColor(src_bin, src_bin, CV_BGR2GRAY);//若读取三通道视频文件,需转换为单通道 + } + StructingElementClose(src_bin, 6, 6);//图像膨胀,防止图像断开并更方便寻找 + imshow("flow strip struct", src_bin); + + 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) { @@ -179,156 +209,217 @@ int Energy::findFlowStrip(const cv::Mat src, int &last_flow_strips_cnt){ continue; } flow_strips.emplace_back(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; -// if(length>20&&width>20){ -// cout<40&&width>5){ +// cout<(flow_strips.size()); return -1;//寻找到的流动条比上一帧少,说明该帧有误,返回-1 } last_flow_strips_cnt = static_cast(flow_strips.size()); return static_cast(flow_strips.size()); + +} + + +//---------------------------------------------------------------------------------------------------------------------- +// 此函数用于框取中心R的寻找范围 +// --------------------------------------------------------------------------------------------------------------------- +void Energy::findCenterROI(const cv::Mat src) { + cv::Mat src_mask = src.clone(); + target_armor.at(0).rect.size.height *= 1.3; + target_armor.at(0).rect.size.width *= 1.3; + Point2f vertices[4]; + vector mask_rect; + target_armor.at(0).rect.points(vertices); //计算矩形的4个顶点 + for (int i = 0; i < 4; i++) + line(src_mask, vertices[i], vertices[(i + 1) % 4], Scalar(0, 0, 0), 15); + imshow("fill", src_mask); + flow_strips_cnt = findFlowStrip(src_mask, last_flow_strips_cnt); + float length = target_armor.at(0).rect.size.height > target_armor.at(0).rect.size.width ? + target_armor.at(0).rect.size.height : target_armor.at(0).rect.size.width; + if (flow_strips_cnt > 0 && target_armor.size() > 0) { + for (auto flow_strip: flow_strips) { + Point2f p2p(flow_strip.rect.center.x - target_point.x, + flow_strip.rect.center.y - target_point.y); + p2p = p2p / pointDistance(flow_strip.rect.center, target_point);//单位化 + center_ROI.emplace_back( + EnergyPart(cv::RotatedRect(cv::Point2f(flow_strip.rect.center + p2p * length * 1.5), + Size2f(length, length), -90))); + } + } } //---------------------------------------------------------------------------------------------------------------------- // 此函数用于判断找到的矩形候选区是否为扇叶 // --------------------------------------------------------------------------------------------------------------------- -bool Energy::isValidFanContour(const vector fan_contour) { - double cur_contour_area = contourArea(fan_contour); - if (cur_contour_area > energy_part_param_.FAN_CONTOUR_AREA_MAX || - cur_contour_area < energy_part_param_.FAN_CONTOUR_AREA_MIN) - { - //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 < energy_part_param_.FAN_CONTOUR_LENGTH_MIN || width < energy_part_param_.FAN_CONTOUR_WIDTH_MIN || - length > energy_part_param_.FAN_CONTOUR_LENGTH_MAX || width > energy_part_param_.FAN_CONTOUR_WIDTH_MAX) - { - //cout<<"length width fail."< energy_part_param_.FAN_CONTOUR_HW_RATIO_MAX || - length_width_ratio < energy_part_param_.FAN_CONTOUR_HW_RATIO_MIN) - { - //cout<<"length width ratio fail."< &fan_contour) { + double cur_contour_area = contourArea(fan_contour); + if (cur_contour_area > energy_part_param_.FAN_CONTOUR_AREA_MAX || + cur_contour_area < energy_part_param_.FAN_CONTOUR_AREA_MIN) { + //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 < energy_part_param_.FAN_CONTOUR_LENGTH_MIN || width < energy_part_param_.FAN_CONTOUR_WIDTH_MIN || + length > energy_part_param_.FAN_CONTOUR_LENGTH_MAX || width > energy_part_param_.FAN_CONTOUR_WIDTH_MAX) { + //cout<<"length width fail."< energy_part_param_.FAN_CONTOUR_HW_RATIO_MAX || + length_width_ratio < energy_part_param_.FAN_CONTOUR_HW_RATIO_MIN) { + //cout<<"length width ratio fail."< armor_contour) { - double cur_contour_area = contourArea(armor_contour); - if (cur_contour_area > energy_part_param_.ARMOR_CONTOUR_AREA_MAX || - cur_contour_area < energy_part_param_.ARMOR_CONTOUR_AREA_MIN) - { - //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 < energy_part_param_.ARMOR_CONTOUR_LENGTH_MIN || width < energy_part_param_.ARMOR_CONTOUR_WIDTH_MIN || - length > energy_part_param_.ARMOR_CONTOUR_LENGTH_MAX||width>energy_part_param_.ARMOR_CONTOUR_WIDTH_MAX) - { - //cout<<"length width fail."< &armor_contour) { + double cur_contour_area = contourArea(armor_contour); + if (cur_contour_area > energy_part_param_.ARMOR_CONTOUR_AREA_MAX || + cur_contour_area < energy_part_param_.ARMOR_CONTOUR_AREA_MIN) { + //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 < energy_part_param_.ARMOR_CONTOUR_LENGTH_MIN || width < energy_part_param_.ARMOR_CONTOUR_WIDTH_MIN || + length > energy_part_param_.ARMOR_CONTOUR_LENGTH_MAX || width > energy_part_param_.ARMOR_CONTOUR_WIDTH_MAX) { + //cout<<"length width fail."< energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MAX || - length_width_ratio < energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MIN) - { - //cout<<"length width ratio fail."< energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MAX || + length_width_ratio < energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MIN) { + //cout<<"length width ratio fail."< center_R_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) - { - //cout< energy_part_param_.ARMOR_CONTOUR_AREA_MAX || + cur_contour_area < energy_part_param_.ARMOR_CONTOUR_AREA_MIN) { + //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 < energy_part_param_.CENTER_R_CONTOUR_LENGTH_MIN || width < energy_part_param_.CENTER_R_CONTOUR_WIDTH_MIN - ||length > energy_part_param_.CENTER_R_CONTOUR_LENGTH_MAX ||width>energy_part_param_.CENTER_R_CONTOUR_WIDTH_MAX) - { + || length > energy_part_param_.CENTER_R_CONTOUR_LENGTH_MAX || + width > energy_part_param_.CENTER_R_CONTOUR_WIDTH_MAX) { //cout<<"length width fail."< energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MAX || - length_width_ratio < energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MIN) - { + length_width_ratio < energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MIN) { //cout<<"length width ratio fail."< intersection; + if (center_ROI.empty() || rotatedRectangleIntersection(cur_rect, center_ROI.at(0).rect, intersection) == 0 || + contourArea(intersection) < energy_part_param_.CENTER_R_CONTOUR_INTERSETION_AREA_MIN) { + return false; + } return true; } +//---------------------------------------------------------------------------------------------------------------------- +// 此函数用于判断找到的矩形候选区是否为流动条扇叶 +// --------------------------------------------------------------------------------------------------------------------- +bool Energy::isValidFlowStripFanContour(const vector &flow_strip_fan_contour) { + double cur_contour_area = contourArea(flow_strip_fan_contour); + if (cur_contour_area > energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MAX || + cur_contour_area < energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MIN) { + //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 < energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MIN + || width < energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MIN + || length > energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MAX + || width > energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MAX) { + //cout<<"length width fail."< energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MAX || + length_width_ratio < energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MIN) { + //cout<<"length width ratio fail."< energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MAX) + //如果ROI为空、或者选区与ROI无重合面积、或者有重合面积但重合面积太小 + return false; + //轮廓对矩形的面积占有率不合适 + return true; +} //---------------------------------------------------------------------------------------------------------------------- // 此函数用于判断找到的矩形候选区是否为流动条 // --------------------------------------------------------------------------------------------------------------------- -bool Energy::isValidFlowStripContour(const vector flow_strip_contour) { +bool Energy::isValidFlowStripContour(const vector &flow_strip_contour) { double cur_contour_area = contourArea(flow_strip_contour); if (cur_contour_area > energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MAX || - cur_contour_area < energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MIN) - { - //cout< 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 < energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MIN - || width < energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MIN - ||length > energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MAX - ||width > energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX) - { - //cout<<"length width fail."< energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MAX || + width > energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX) { +// cout<<"length width fail."< energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MAX || - length_width_ratio < energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN) - { - //cout<<"length width ratio fail."< energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MAX) return false; - //轮廓对矩形的面积占有率不合适 + if (cur_contour_area / cur_size.area() < energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MIN) + return false;//轮廓对矩形的面积占有率不合适 + std::vector intersection; + if (flow_strip_fans.size() > 0 && + rotatedRectangleIntersection(cur_rect, flow_strip_fans.at(0).rect, intersection) != 0) { + if (contourArea(intersection) < energy_part_param_.FLOW_STRIP_CONTOUR_INTERSETION_AREA_MIN) { + return false; + } + } return true; -} \ No newline at end of file +} diff --git a/energy/src/energy/find/target_finder.cpp b/energy/src/energy/find/target_finder.cpp index 2ee4349..5081047 100644 --- a/energy/src/energy/find/target_finder.cpp +++ b/energy/src/energy/find/target_finder.cpp @@ -98,16 +98,17 @@ void Energy::findTargetByIntersection() { //---------------------------------------------------------------------------------------------------------------------- // 此函数在流动条区域内寻找装甲板 // --------------------------------------------------------------------------------------------------------------------- -bool Energy::findTargetInFlowStrip(){ +bool Energy::findTargetInFlowStripFan(){ int i = 0; for(i=0; i intersection; - if(rotatedRectangleIntersection(armors.at(i).rect, flow_strips.at(0).rect, intersection)==0) + if(rotatedRectangleIntersection(armors.at(i).rect, flow_strip_fans.at(0).rect, intersection)==0) continue;//返回0表示没有重合面积 double cur_contour_area = contourArea(intersection); if(cur_contour_area < energy_part_param_.INTERSETION_CONTOUR_AREA_MIN) continue; else{ + target_armor.emplace_back(armors.at(i)); target_point = armors.at(i).rect.center; return true; } diff --git a/energy/src/energy/run.cpp b/energy/src/energy/run.cpp index a79619a..004dddc 100644 --- a/energy/src/energy/run.cpp +++ b/energy/src/energy/run.cpp @@ -77,7 +77,10 @@ int Energy::runBig(cv::Mat &gimble_src){ fans.clear(); armors.clear(); centerRs.clear(); + flow_strip_fans.clear(); flow_strips.clear(); + center_ROI.clear(); + target_armor.clear(); fan_polar_angle.clear(); armor_polar_angle.clear(); @@ -98,9 +101,10 @@ int Energy::runBig(cv::Mat &gimble_src){ getAllArmorCenters(); circleLeastFit(); - flow_strips_cnt = findFlowStrip(gimble_src, last_flow_strips_cnt); - if(flow_strips_cnt == 1 && findTargetInFlowStrip()){ - showFlowStripContours("strip", gimble_src); + flow_strip_fans_cnt = findFlowStripFan(gimble_src, last_flow_strip_fans_cnt); + if(flow_strip_fans_cnt == 1 && findTargetInFlowStripFan()){ + findCenterROI(gimble_src); + showFlowStripFanContours("strip", gimble_src); }else{ fans_cnt = findFan(gimble_src, last_fans_cnt); if(fans_cnt==-1) return 0;//滤去漏判的帧 @@ -114,7 +118,7 @@ int Energy::runBig(cv::Mat &gimble_src){ } centerRs_cnt = findCenterR(gimble_src); -// if(centerRs_cnt>0)showCenterRContours("R", gimble_src); + if(centerRs_cnt>0)showCenterRContours("R", gimble_src); writeDownMark(); diff --git a/energy/src/energy/show/show.cpp b/energy/src/energy/show/show.cpp index d68938d..8a8bd97 100644 --- a/energy/src/energy/show/show.cpp +++ b/energy/src/energy/show/show.cpp @@ -139,7 +139,7 @@ void Energy::showCenterRContours(std::string windows_name, const cv::Mat src) { //---------------------------------------------------------------------------------------------------------------------- // 此函数用于显示图像中所有流动条 // --------------------------------------------------------------------------------------------------------------------- -void Energy::showFlowStripContours(std::string windows_name, const cv::Mat src) { +void Energy::showFlowStripFanContours(std::string windows_name, const cv::Mat src) { if (src.empty())return; static Mat image2show; @@ -151,23 +151,36 @@ void Energy::showFlowStripContours(std::string windows_name, const cv::Mat src) { image2show = src.clone(); } + for (const auto &flow_strip_fan : flow_strip_fans) + { + Point2f vertices[4]; //定义矩形的4个顶点 + flow_strip_fan.rect.points(vertices); //计算矩形的4个顶点 + for (int i = 0; i < 4; i++) + line(image2show, vertices[i], vertices[(i + 1) % 4], Scalar(127, 127, 255), 2); + } for (const auto &flow_strip : flow_strips) { Point2f vertices[4]; //定义矩形的4个顶点 flow_strip.rect.points(vertices); //计算矩形的4个顶点 for (int i = 0; i < 4; i++) - line(image2show, vertices[i], vertices[(i + 1) % 4], Scalar(127, 127, 255), 2); + line(image2show, vertices[i], vertices[(i + 1) % 4], Scalar(0, 255, 0), 2); } - for (const auto &armor : armors) - { + for (const auto &armor : armors){ if(pointDistance(armor.rect.center, target_point) < energy_part_param_.TWIN_POINT_MAX){ Point2f vertices[4]; //定义矩形的4个顶点 armor.rect.points(vertices); //计算矩形的4个顶点 for (int i = 0; i < 4; i++) line(image2show, vertices[i], vertices[(i + 1) % 4], Scalar(255, 255, 0), 2); } - } + } + Point2f vertices[4]; //定义矩形的4个顶点 + if(center_ROI.size() > 0){ + center_ROI.at(0).rect.points(vertices); //计算矩形的4个顶点 + for (int i = 0; i < 4; i++) + line(image2show, vertices[i], vertices[(i + 1) % 4], Scalar(0, 0, 255), 2); + } imshow(windows_name, image2show); } + diff --git a/main.cpp b/main.cpp index 9f2d72f..2bd6bb2 100644 --- a/main.cpp +++ b/main.cpp @@ -21,7 +21,7 @@ using namespace std; mcu_data mcuData = { // 单片机端回传结构体 0, // 当前云台yaw角 0, // 当前云台pitch角 - ARMOR_STATE, // 当前状态,自瞄-大符-小符 + SMALL_ENERGY_STATE, // 当前状态,自瞄-大符-小符 0, // 云台角度标记位 1, // 是否启用数字识别 ENEMY_RED, // 敌方颜色 @@ -53,7 +53,7 @@ int main(int argc, char *argv[]) { video_gimble = new CameraWrapper(0/*, "armor"*/); video_chassis = new CameraWrapper(1/*, "energy"*/); } else { - video_gimble = new VideoWrapper("/home/sun/项目/energy_video/official_r_l.mp4"); + video_gimble = new VideoWrapper("/home/sun/项目/energy_video/energy_test.avi"); video_chassis = new VideoWrapper("/home/sun/项目/energy_video/energy_test.avi"); } if (video_gimble->init()) { @@ -114,9 +114,9 @@ int main(int argc, char *argv[]) { energy.runBig(gimble_src); } } +// cv::waitKey(3); }); } while (ok); - delete video_gimble; video_gimble = nullptr; delete video_chassis;