Merge remote-tracking branch 'origin/anti-top'

# Conflicts:
#	armor/src/armor_finder/send_target/send_target.cpp
#	energy/src/energy/clear/energy_init.cpp
#	energy/src/energy/find/energy_finder.cpp
#	energy/src/energy/judge/judge_contour.cpp
#	energy/src/energy/run.cpp
#	main.cpp
#	others/src/camera/camera_wrapper.cpp
This commit is contained in:
wanpiqiu123
2019-07-22 09:27:16 +08:00
46 changed files with 27899 additions and 18853 deletions

View File

@@ -6,6 +6,7 @@
#define _ARMOR_FINDER_H_ #define _ARMOR_FINDER_H_
#include <map> #include <map>
#include <sys/time.h>
#include <constants.h> #include <constants.h>
#include <opencv2/core.hpp> #include <opencv2/core.hpp>
#include <opencv2/tracking.hpp> #include <opencv2/tracking.hpp>
@@ -13,30 +14,73 @@
#include <armor_finder/classifier/classifier.h> #include <armor_finder/classifier/classifier.h>
#include <additions/additions.h> #include <additions/additions.h>
#define BLOB_RED ENEMY_RED #define BLOB_RED ENEMY_RED
#define BLOB_BLUE ENEMY_BLUE #define BLOB_BLUE ENEMY_BLUE
#define DISTANCE_HEIGHT_5MM (113.0) // 单位: m*pixel #define BOX_RED ENEMY_RED
#define BOX_BLUE ENEMY_BLUE
#define DISTANCE_HEIGHT_5MM (107.0) // 单位: m*pixel
#define DISTANCE_HEIGHT DISTANCE_HEIGHT_5MM #define DISTANCE_HEIGHT DISTANCE_HEIGHT_5MM
#define B1 1
#define B2 2
#define B3 3
#define B4 4
#define B5 5
#define B7 6
#define B8 7
#define R1 8
#define R2 9
#define R3 10
#define R4 11
#define R5 12
#define R7 13
#define R8 14
extern std::map<int, string> id2name; //装甲板id到名称的map extern std::map<int, string> id2name; //装甲板id到名称的map
extern std::map<string, int> name2id; //装甲板名称到id的map extern std::map<string, int> name2id; //装甲板名称到id的map
/******************* 灯条类定义 ***********************/ /******************* 灯条类定义 ***********************/
class LightBlob { class LightBlob {
public: public:
cv::RotatedRect rect; //灯条位置 cv::RotatedRect rect; //灯条位置
double length; //灯条长度 double length; //灯条长度
uint8_t BlobColor; //灯条颜色 uint8_t blob_color; //灯条颜色
LightBlob(cv::RotatedRect &r) : rect(r) { LightBlob(cv::RotatedRect &r, uint8_t color) : rect(r), blob_color(color) {
length = max(rect.size.height, rect.size.width); length = max(rect.size.height, rect.size.width);
}; };
LightBlob() = default;
}; };
typedef std::vector<LightBlob> LightBlobs; typedef std::vector<LightBlob> LightBlobs;
/******************* 装甲板类定义 **********************/
class ArmorBox{
public:
typedef enum{
FRONT, SIDE, UNKNOWN
} BoxOrientation;
cv::Rect2d rect;
LightBlobs light_blobs;
uint8_t box_color;
int id;
explicit ArmorBox(const cv::Rect &pos=cv::Rect2d(), const LightBlobs &blobs=LightBlobs(), uint8_t color=0, int i=0);
double blobsDistance() const;
double lengthRatio() const;
double lengthDistanceRatio() const;
double getDistance() const;
BoxOrientation getOrientation() const;
};
typedef std::vector<ArmorBox> ArmorBoxes;
/********************* 自瞄类定义 **********************/ /********************* 自瞄类定义 **********************/
class ArmorFinder{ class ArmorFinder{
public: public:
@@ -50,30 +94,36 @@ private:
SEARCHING_STATE, TRACKING_STATE, STANDBY_STATE SEARCHING_STATE, TRACKING_STATE, STANDBY_STATE
} State; // 自瞄状态枚举定义 } State; // 自瞄状态枚举定义
cv::Mat src_raw; // 当前原图 typedef enum{
NORMAL, ANTI_TOP
} AntiTopState;
const uint8_t &enemy_color; // 敌方颜色,引用外部变量,自动变化 const uint8_t &enemy_color; // 敌方颜色,引用外部变量,自动变化
State state; // 自瞄状态对象实例 State state; // 自瞄状态对象实例
cv::Rect2d armor_box; // 当前目标位置 ArmorBox armor_box; // 当前目标装甲板
int boxid; // 当前目标id
cv::Ptr<cv::Tracker> tracker; // tracker对象实例 cv::Ptr<cv::Tracker> tracker; // tracker对象实例
Classifier classifier; // CNN分类器对象实例用于数字识别 Classifier classifier; // CNN分类器对象实例用于数字识别
int contour_area; // 装甲区域亮点个数,用于数字识别未启用时判断是否跟丢(已弃用) int contour_area; // 装甲区域亮点个数,用于数字识别未启用时判断是否跟丢(已弃用)
int tracking_cnt; // 记录追踪帧数,用于定时退出追踪 int tracking_cnt; // 记录追踪帧数,用于定时退出追踪
Serial &serial; // 串口对象,引用外部变量,用于和能量机关共享同一个变量 Serial &serial; // 串口对象,引用外部变量,用于和能量机关共享同一个变量
const uint8_t &use_classifier; // 标记是否启用CNN分类器引用外部变量自动变化 const uint8_t &use_classifier; // 标记是否启用CNN分类器引用外部变量自动变化
ArmorBox::BoxOrientation last_orient; // 上一帧目标装甲板方向,用于反陀螺
timeval last_front_time; // 上一次发生装甲板方向切换的时间
int anti_top_cnt; // 满足条件的装甲板方向切换持续次数,用于反陀螺
AntiTopState anti_top_state; // 当前是否识别到陀螺
bool findLightBlobs(const cv::Mat &src, LightBlobs &light_blobs);
bool findArmorBox(const cv::Mat &src, ArmorBox &box);
bool stateSearchingTarget(cv::Mat &src); // searching state主函数 bool stateSearchingTarget(cv::Mat &src); // searching state主函数
bool stateTrackingTarget(cv::Mat &src); // tracking state主函数 bool stateTrackingTarget(cv::Mat &src); // tracking state主函数
bool stateStandBy(); // stand by state主函数已弃用 bool stateStandBy(); // stand by state主函数已弃用
bool findLightBlobs(const cv::Mat &src_bin, // 在二值图上寻找灯条 void antiTop(); // 反小陀螺
LightBlobs &light_blobs);
bool findArmorBoxes(const LightBlobs &light_blobs, // 根据灯条匹配装甲板候选区
std::vector<cv::Rect2d> &armor_boxes);
public: public:
void run(cv::Mat &src); // 自瞄主函数 void run(cv::Mat &src); // 自瞄主函数
bool sendBoxPosition(); // 和主控板通讯 bool sendBoxPosition(uint16_t shoot); // 和主控板通讯
}; };
#endif /* _ARMOR_FINDER_H_ */ #endif /* _ARMOR_FINDER_H_ */

View File

@@ -9,9 +9,10 @@
#include <armor_finder/armor_finder.h> #include <armor_finder/armor_finder.h>
// //
void showArmorBoxVector(std::string windows_name, const cv::Mat &src, const std::vector<cv::Rect2d> &armor_box); void showArmorBoxes(std::string windows_name, const cv::Mat &src, const ArmorBoxes &armor_boxes);
void showArmorBox(std::string windows_name, const cv::Mat &src, cv::Rect2d armor_box, int boxid); void showArmorBox(std::string windows_name, const cv::Mat &src, const ArmorBox &armor_box);
void showContours(std::string windows_name, const cv::Mat &src, const std::vector<LightBlob> &light_blobs); void showLightBlobs(std::string windows_name, const cv::Mat &src, const LightBlobs &light_blobs);
void showArmorBoxClass(std::string window_names, const cv::Mat &src, vector<cv::Rect2d> boxes[10]); void showArmorBoxesClass(std::string window_names, const cv::Mat &src, const ArmorBoxes boxes[15]);
void showTrackSearchingPos(std::string window_names, const cv::Mat &src, const cv::Rect2d pos);
#endif /* _SHOW_IMAGES_H_ */ #endif /* _SHOW_IMAGES_H_ */

View File

@@ -0,0 +1,66 @@
//
// Created by xinyang on 19-7-15.
//
#include <armor_finder/armor_finder.h>
#include <log.h>
static double getTimeIntervalms(const timeval& now, const timeval &last){
return (now.tv_sec-last.tv_sec)*1000.0 + (now.tv_usec-last.tv_usec)/1000.0;
}
void ArmorFinder::antiTop() {
static double top_periodms = 0;
static double last_top_periodms = 0;
uint16_t shoot_delay = 0;
timeval curr_time;
// if(anti_top_state == ANTI_TOP){
// cout << "anti top" << endl;
// }else if(anti_top_state == NORMAL){
// cout << "Normal" << endl;
// }
gettimeofday(&curr_time, nullptr);
auto interval = getTimeIntervalms(curr_time, last_front_time);
if(interval > 700){
anti_top_state = NORMAL;
anti_top_cnt = 0;
}
ArmorBox::BoxOrientation orientation = armor_box.getOrientation();
if(orientation == ArmorBox::UNKNOWN){
if(anti_top_state == NORMAL){
sendBoxPosition(shoot_delay);
}
return;
}
if(orientation!=last_orient && orientation==ArmorBox::FRONT){
last_front_time = curr_time;
if(150<interval && interval<700){
if(anti_top_state == ANTI_TOP){
last_top_periodms = top_periodms;
top_periodms = interval;
LOGM(STR_CTR(WORD_LIGHT_GREEN, "top period: %.1lf ms"), top_periodms);
shoot_delay = (last_top_periodms+top_periodms)/2.0-110;
last_orient = orientation;
}else if(anti_top_state == NORMAL){
// LOGM("interval:%.1lf", interval);
if(++anti_top_cnt > 4){
anti_top_state = ANTI_TOP;
}
}
}
}
if(anti_top_state == ANTI_TOP){
if(orientation == ArmorBox::FRONT){
sendBoxPosition(shoot_delay);
}
}else if(anti_top_state == NORMAL){
sendBoxPosition(shoot_delay);
}
last_orient = orientation;
}

View File

@@ -0,0 +1,81 @@
//
// Created by xinyang on 19-7-13.
//
#include <armor_finder/armor_finder.h>
#include <log.h>
ArmorBox::ArmorBox(const cv::Rect &pos, const LightBlobs &blobs, uint8_t color, int i) :
rect(pos), light_blobs(blobs), box_color(color), id(i){};
double ArmorBox::blobsDistance() const{
if(light_blobs.size() == 2){
auto &x = light_blobs[0].rect.center;
auto &y = light_blobs[1].rect.center;
return sqrt((x.x-y.x)*(x.x-y.x) + (x.y-y.y)*(x.y-y.y));
}else{
return 0;
}
}
double ArmorBox::lengthRatio() const{
if(light_blobs.size() == 2){
return light_blobs[0].length / light_blobs[1].length < 1 ?
(light_blobs[0].length / light_blobs[1].length) :
(light_blobs[1].length / light_blobs[0].length);
}else{
return 0;
}
}
double ArmorBox::lengthDistanceRatio() const {
if(light_blobs.size() == 2){
return max(light_blobs[0].length, light_blobs[1].length)
/ blobsDistance();
}else{
return 100;
}
}
double ArmorBox::getDistance() const{
if(light_blobs.size() == 2 ){
return DISTANCE_HEIGHT / 2 / max(light_blobs[0].length, light_blobs[1].length);
} else {
return DISTANCE_HEIGHT / rect.height;
}
}
ArmorBox::BoxOrientation ArmorBox::getOrientation() const{
// cout << lengthDistanceRatio() << endl;
if(light_blobs.size() != 2){
return UNKNOWN;
}
switch (id) {
case R1:
case R7:
case R8:
case B1:
case B7:
case B8:
if(lengthDistanceRatio() < 0.24){
return FRONT;
}else{
return SIDE;
}
case R2:
case R3:
case R4:
case R5:
case B2:
case B3:
case B4:
case B5:
if (lengthDistanceRatio() < 0.48) {
return FRONT;
}else{
return SIDE;
}
default:
return UNKNOWN;
}
}

View File

@@ -42,32 +42,25 @@ ArmorFinder::ArmorFinder(uint8_t &color, Serial &u, const string &paras_folder,
classifier(paras_folder), classifier(paras_folder),
contour_area(0), contour_area(0),
use_classifier(use), use_classifier(use),
boxid(-1),
tracking_cnt(0) { tracking_cnt(0) {
} }
void ArmorFinder::run(cv::Mat &src) { void ArmorFinder::run(cv::Mat &src) {
src_raw = src; // stateSearchingTarget(src); // for debug
cv::Mat src_use = src.clone(); // 实际参与计算的图像对象 // goto end;
if (show_armor_box) { // 根据条件显示当前目标装甲板
showArmorBox("box", src, armor_box, boxid);
cv::waitKey(1);
}
// stateSearchingTarget(src_use); // for debug
// return;
switch (state) { switch (state) {
case SEARCHING_STATE: case SEARCHING_STATE:
if (stateSearchingTarget(src_use)) { if (stateSearchingTarget(src)) {
if ((armor_box & cv::Rect2d(0, 0, 640, 480)) == armor_box) { // 判断装甲板区域是否脱离图像区域 // cout << armor_box.rect << endl;
if ((armor_box.rect & cv::Rect2d(0, 0, 640, 480)) == armor_box.rect) { // 判断装甲板区域是否脱离图像区域
if (!classifier || !use_classifier) { /* 如果分类器不可用或者不使用分类器 */ if (!classifier || !use_classifier) { /* 如果分类器不可用或者不使用分类器 */
cv::Mat roi = src_use.clone()(armor_box), roi_gray; /* 就使用装甲区域亮点数判断是否跟丢 */ cv::Mat roi = src(armor_box.rect).clone(), roi_gray; /* 就使用装甲区域亮点数判断是否跟丢 */
cv::cvtColor(roi, roi_gray, CV_RGB2GRAY); cv::cvtColor(roi, roi_gray, CV_RGB2GRAY);
cv::threshold(roi_gray, roi_gray, 180, 255, cv::THRESH_BINARY); cv::threshold(roi_gray, roi_gray, 180, 255, cv::THRESH_BINARY);
contour_area = cv::countNonZero(roi_gray); contour_area = cv::countNonZero(roi_gray);
} }
tracker = TrackerToUse::create(); // 成功搜寻到装甲板创建tracker对象 tracker = TrackerToUse::create(); // 成功搜寻到装甲板创建tracker对象
tracker->init(src_use, armor_box); tracker->init(src, armor_box.rect);
state = TRACKING_STATE; state = TRACKING_STATE;
tracking_cnt = 0; tracking_cnt = 0;
LOGM(STR_CTR(WORD_LIGHT_CYAN, "into track")); LOGM(STR_CTR(WORD_LIGHT_CYAN, "into track"));
@@ -75,7 +68,7 @@ void ArmorFinder::run(cv::Mat &src) {
} }
break; break;
case TRACKING_STATE: case TRACKING_STATE:
if (!stateTrackingTarget(src_use) || ++tracking_cnt > 100) { // 最多追踪100帧图像 if (!stateTrackingTarget(src) || ++tracking_cnt > 100) { // 最多追踪100帧图像
state = SEARCHING_STATE; state = SEARCHING_STATE;
LOGM(STR_CTR(WORD_LIGHT_YELLOW, "into search!")); LOGM(STR_CTR(WORD_LIGHT_YELLOW, "into search!"));
} }
@@ -84,5 +77,12 @@ void ArmorFinder::run(cv::Mat &src) {
default: default:
stateStandBy(); stateStandBy();
} }
end:
antiTop();
if (show_armor_box) { // 根据条件显示当前目标装甲板
showArmorBox("box", src, armor_box);
cv::waitKey(1);
}
} }

View File

@@ -0,0 +1,201 @@
//
// Created by xinyang on 19-7-18.
//
#include <armor_finder/armor_finder.h>
#include <show_images/show_images.h>
#include <options/options.h>
#include <opencv2/highgui.hpp>
#include <log.h>
static string prior_blue[] = {
"B8", "B1", "B3", "B4", "B5", "B7", "B2",
"R8", "R1", "R3", "R4", "R5", "R7", "R2",
};
static string prior_red[] = {
"R8", "R1", "R3", "R4", "R5", "R7", "R2",
"B8", "B1", "B3", "B4", "B5", "B7", "B2",
};
static bool angelJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
float angle_i = light_blob_i.rect.size.width > light_blob_i.rect.size.height ? light_blob_i.rect.angle :
light_blob_i.rect.angle - 90;
float angle_j = light_blob_j.rect.size.width > light_blob_j.rect.size.height ? light_blob_j.rect.angle :
light_blob_j.rect.angle - 90;
return abs(angle_i - angle_j) < 20;
}
static bool heightJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
cv::Point2f centers = light_blob_i.rect.center - light_blob_j.rect.center;
return abs(centers.y) < 30;
}
static bool lengthJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
double side_length;
cv::Point2f centers = light_blob_i.rect.center - light_blob_j.rect.center;
side_length = sqrt(centers.ddot(centers));
return (side_length / light_blob_i.length < 8 && side_length / light_blob_i.length > 0.5);
}
static bool lengthRatioJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
return (light_blob_i.length / light_blob_j.length < 2.5
&& light_blob_i.length / light_blob_j.length > 0.4);
}
/* 判断两个灯条的错位度,不知道英文是什么!!! */
static bool CuoWeiDuJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
float angle_i = light_blob_i.rect.size.width > light_blob_i.rect.size.height ? light_blob_i.rect.angle :
light_blob_i.rect.angle - 90;
float angle_j = light_blob_j.rect.size.width > light_blob_j.rect.size.height ? light_blob_j.rect.angle :
light_blob_j.rect.angle - 90;
float angle = (angle_i + angle_j) / 2.0 / 180.0 * 3.14159265459;
if (abs(angle_i - angle_j) > 90) {
angle += 3.14159265459 / 2;
}
Vector2f orientation(cos(angle), sin(angle));
Vector2f p2p(light_blob_j.rect.center.x - light_blob_i.rect.center.x,
light_blob_j.rect.center.y - light_blob_i.rect.center.y);
return abs(orientation.dot(p2p)) < 25;
}
static bool boxAngleJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
float angle_i = light_blob_i.rect.size.width > light_blob_i.rect.size.height ? light_blob_i.rect.angle :
light_blob_i.rect.angle - 90;
float angle_j = light_blob_j.rect.size.width > light_blob_j.rect.size.height ? light_blob_j.rect.angle :
light_blob_j.rect.angle - 90;
float angle = (angle_i + angle_j) / 2.0;
if (abs(angle_i - angle_j) > 90) {
angle += 90.0;
}
return (-120.0 < angle && angle < -60.0) || (60.0 < angle && angle < 120.0);
}
static bool isCoupleLight(const LightBlob &light_blob_i, const LightBlob &light_blob_j, uint8_t enemy_color) {
return light_blob_i.blob_color == enemy_color &&
light_blob_j.blob_color == enemy_color &&
lengthRatioJudge(light_blob_i, light_blob_j) &&
lengthJudge(light_blob_i, light_blob_j) &&
// heightJudge(light_blob_i, light_blob_j) &&
angelJudge(light_blob_i, light_blob_j) &&
boxAngleJudge(light_blob_i, light_blob_j) &&
CuoWeiDuJudge(light_blob_i, light_blob_j);
}
static double centerDistance(const cv::Rect2d &box) {
double dx = box.x - box.width / 2 - 320;
double dy = box.y - box.height / 2 - 240;
return dx * dx + dy * dy;
}
bool matchArmorBoxes(const cv::Mat &src, const LightBlobs &light_blobs, ArmorBoxes &armor_boxes, uint8_t color) {
armor_boxes.clear();
for (int i = 0; i < light_blobs.size() - 1; ++i) {
for (int j = i + 1; j < light_blobs.size(); ++j) {
if (!isCoupleLight(light_blobs.at(i), light_blobs.at(j), color)) {
// cout << "match fail" << endl;
continue;
}
cv::Rect2d rect_left = light_blobs.at(static_cast<unsigned long>(i)).rect.boundingRect();
cv::Rect2d rect_right = light_blobs.at(static_cast<unsigned long>(j)).rect.boundingRect();
double min_x, min_y, max_x, max_y;
min_x = fmin(rect_left.x, rect_right.x) - 4;
max_x = fmax(rect_left.x + rect_left.width, rect_right.x + rect_right.width) + 4;
min_y = fmin(rect_left.y, rect_right.y) - 0.5 * (rect_left.height + rect_right.height) / 2.0;
max_y = fmax(rect_left.y + rect_left.height, rect_right.y + rect_right.height) +
0.5 * (rect_left.height + rect_right.height) / 2.0;
if (min_x < 0 || max_x > src.cols || min_y < 0 || max_y > src.rows) {
// cout << "out of range" << endl;
continue;
}
LightBlobs pair_blobs = {light_blobs.at(i), light_blobs.at(j)};
armor_boxes.emplace_back(
cv::Rect2d(min_x, min_y, max_x - min_x, max_y - min_y),
pair_blobs,
color
);
}
}
if (armor_boxes.empty()) {
return false;
}
sort(armor_boxes.begin(), armor_boxes.end(), [](ArmorBox box1, ArmorBox box2) -> bool {
return centerDistance(box1.rect) < centerDistance(box2.rect);
});
return true;
}
bool ArmorFinder::findArmorBox(const cv::Mat &src, ArmorBox &box){
LightBlobs light_blobs; // 存储所有可能的灯条
ArmorBoxes armor_boxes; // 装甲板候选区
ArmorBoxes boxes_number[15]; // 装甲板候选区放置在对应id位置
box.rect = cv::Rect2d(0,0,0,0);
box.id = -1;
if (!findLightBlobs(src, light_blobs)) {
return false;
}
if (show_light_blobs && src.size()==cv::Size(640, 480)) {
showLightBlobs("light_blobs", src, light_blobs);
cv::waitKey(1);
}
if (!matchArmorBoxes(src, light_blobs, armor_boxes, enemy_color)) {
// cout << "Box fail!" << endl;
return false;
}
if (show_armor_boxes && src.size()==cv::Size(640, 480)) {
showArmorBoxes("boxes", src, armor_boxes);
cv::waitKey(1);
}
if (classifier && use_classifier) {
for (auto &armor_box : armor_boxes) {
cv::Mat roi = src(armor_box.rect).clone();
cv::resize(roi, roi, cv::Size(48, 36));
int c = classifier(roi);
armor_box.id = c;
boxes_number[c].emplace_back(armor_box);
}
if (enemy_color == ENEMY_BLUE) {
for (auto &name : prior_blue) {
if (!boxes_number[name2id[name]].empty()) {
box = boxes_number[name2id[name]][0];
break;
}
}
} else if (enemy_color == ENEMY_RED) {
for (auto &name : prior_red) {
if (!boxes_number[name2id[name]].empty()) {
box = boxes_number[name2id[name]][0];
break;
}
}
} else {
LOGE_INFO("enemy_color ERROR!");
}
if (save_labelled_boxes) {
for (int i = 0; i < sizeof(boxes_number) / sizeof(boxes_number[0]); i++) {
for (auto &armor_box : boxes_number[i]) {
char filename[100];
sprintf(filename, PROJECT_DIR"/armor_box_photo/%s_%d.jpg", id2name[i].data(),
time(nullptr) + clock());
cv::imwrite(filename, src(armor_box.rect));
}
}
}
if (box.rect == cv::Rect2d(0, 0, 0, 0)) {
return false;
}
if (show_armor_boxes && src.size()==cv::Size(640, 480)) {
showArmorBoxesClass("class", src, boxes_number);
}
} else {
box = armor_boxes[0];
}
return true;
}

View File

@@ -0,0 +1,157 @@
//
// Created by xinyang on 19-7-10.
//
#include <armor_finder/armor_finder.h>
#include <options/options.h>
#include <opencv2/highgui.hpp>
static double lw_rate(const cv::RotatedRect &rect) {
return rect.size.height > rect.size.width ?
rect.size.height / rect.size.width :
rect.size.width / rect.size.height;
}
static double areaRatio(const std::vector<cv::Point> &contour, const cv::RotatedRect &rect){
return cv::contourArea(contour) / rect.size.area();
}
static bool isValidLightBlob(const std::vector<cv::Point> &contour, const cv::RotatedRect &rect) {
return (1.5 < lw_rate(rect) && lw_rate(rect) < 10) &&
// (rect.size.area() < 3000) &&
((rect.size.area() < 50 && areaRatio(contour, rect) > 0.4) ||
(rect.size.area() >= 50 && areaRatio(contour, rect) > 0.6));
}
// 此函数可以有性能优化.
static uint8_t get_blob_color(const cv::Mat &src, const cv::RotatedRect &blobPos) {
auto region = blobPos.boundingRect();
region.x -= fmax(2, region.width * 0.1);
region.y -= fmax(2, region.height * 0.05);
region.width += 2 * fmax(2, region.width * 0.1);
region.height += 2 * fmax(2, region.height * 0.05);
region &= cv::Rect(0, 0, src.cols, src.rows);
cv::Mat roi = src(region);
int red_cnt = 0, blue_cnt = 0;
for (int row = 0; row < roi.rows; row++) {
for (int col = 0; col < roi.cols; col++) {
red_cnt += roi.at<cv::Vec3b>(row, col)[2];
blue_cnt += roi.at<cv::Vec3b>(row, col)[0];
}
}
if (red_cnt > blue_cnt) {
return BLOB_RED;
} else {
return BLOB_BLUE;
}
}
static float linePointX(const cv::Point2f &p1, const cv::Point2f &p2, int y) {
return (p2.x - p1.x) / (p2.y - p1.y) * (y - p1.y) + p1.x;
}
/// Todo:性能优化后的函数(还有点问题)
static double get_blob_color_opt(const cv::Mat &src, cv::RotatedRect blobPos) {
int blue_cnt=0, red_cnt=0;
blobPos.size.height *= 1.05;
blobPos.size.width *= 1.1;
cv::Point2f corners[4];
blobPos.points(corners);
sort(corners, &corners[4], [](cv::Point2f p1, cv::Point2f p2) {
return p1.y < p2.y;
});
for (int r = corners[0].y; r < corners[1].y; r++) {
auto start = min(linePointX(corners[0], corners[1], r), linePointX(corners[0], corners[2], r)) - 1;
auto end = max(linePointX(corners[0], corners[1], r), linePointX(corners[0], corners[2], r)) + 1;
if (start < 0 || end > 640) return 0;
for (int c = start; c < end; c++) {
red_cnt += src.at<cv::Vec3b>(r, c)[2];
blue_cnt += src.at<cv::Vec3b>(r, c)[0];
}
}
for (int r = corners[1].y; r < corners[2].y; r++) {
auto start = min(linePointX(corners[0], corners[2], r), linePointX(corners[1], corners[3], r)) - 1;
auto end = max(linePointX(corners[0], corners[2], r), linePointX(corners[1], corners[3], r)) + 1;
if (start < 0 || end > 640) return 0;
for (int c = start; c < end; c++) {
red_cnt += src.at<cv::Vec3b>(r, c)[2];
blue_cnt += src.at<cv::Vec3b>(r, c)[0];
}
}
for (int r = corners[2].y; r < corners[3].y; r++) {
auto start = min(linePointX(corners[1], corners[3], r), linePointX(corners[2], corners[3], r)) - 1;
auto end = max(linePointX(corners[1], corners[3], r), linePointX(corners[2], corners[3], r)) + 1;
if (start < 0 || end > 640) return 0;
for (int c = start; c < end; c++) {
red_cnt += src.at<cv::Vec3b>(r, c)[2];
blue_cnt += src.at<cv::Vec3b>(r, c)[0];
}
}
if (red_cnt > blue_cnt) {
return BLOB_RED;
} else {
return BLOB_BLUE;
}
}
static void imagePreProcess(cv::Mat &src) {
static cv::Mat kernel_erode = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 5));
erode(src, src, kernel_erode);
static cv::Mat kernel_dilate = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 5));
dilate(src, src, kernel_dilate);
static cv::Mat kernel_dilate2 = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 5));
dilate(src, src, kernel_dilate2);
static cv::Mat kernel_erode2 = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 5));
erode(src, src, kernel_erode2);
// float alpha = 1.5;
// int beta = 0;
// src.convertTo(src, -1, alpha, beta);
}
bool ArmorFinder::findLightBlobs(const cv::Mat &src, LightBlobs &light_blobs) {
cv::Mat color_channel;
cv::Mat src_bin_light, src_bin_dim;
std::vector<cv::Mat> channels; // 通道拆分
cv::split(src, channels); /************************/
if (enemy_color == ENEMY_BLUE){ /* */
color_channel = channels[0]; /* 根据目标颜色进行通道提取 */
}else if (enemy_color == ENEMY_RED){ /* */
color_channel = channels[2]; /************************/
}
cv::threshold(color_channel, src_bin_light, 200, 255, CV_THRESH_BINARY); // 二值化对应通道
imagePreProcess(src_bin_light); // 开闭运算
cv::threshold(color_channel, src_bin_dim, 160, 255, CV_THRESH_BINARY); // 二值化对应通道
imagePreProcess(src_bin_dim); // 开闭运算
if(src_bin_light.size() == cv::Size(640, 480) && show_light_blobs) {
imshow("bin_light", src_bin_light);
imshow("bin_dim", src_bin_dim);
}
std::vector<std::vector<cv::Point> > light_contours_light, light_contours_dim;
cv::findContours(src_bin_light, light_contours_light, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
cv::findContours(src_bin_dim, light_contours_dim, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
for (auto &light_contour : light_contours_light) {
cv::RotatedRect rect = cv::minAreaRect(light_contour);
if (isValidLightBlob(light_contour, rect)) {
light_blobs.emplace_back(rect, get_blob_color(src, rect));
}
}
for (auto &light_contour : light_contours_dim) {
cv::RotatedRect rect = cv::minAreaRect(light_contour);
if (isValidLightBlob(light_contour, rect)) {
light_blobs.emplace_back(rect, get_blob_color(src, rect));
}
}
return light_blobs.size() >= 2;
}

View File

@@ -1,105 +0,0 @@
//
// Created by xinyang on 19-7-10.
//
#include <armor_finder/armor_finder.h>
static bool angelJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
float angle_i = light_blob_i.rect.size.width > light_blob_i.rect.size.height ? light_blob_i.rect.angle :
light_blob_i.rect.angle - 90;
float angle_j = light_blob_j.rect.size.width > light_blob_j.rect.size.height ? light_blob_j.rect.angle :
light_blob_j.rect.angle - 90;
return abs(angle_i - angle_j) < 10;
}
static bool heightJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
cv::Point2f centers = light_blob_i.rect.center - light_blob_j.rect.center;
return abs(centers.y) < 30;
}
static bool lengthJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
double side_length;
cv::Point2f centers = light_blob_i.rect.center - light_blob_j.rect.center;
side_length = sqrt(centers.ddot(centers));
return (side_length / light_blob_i.length < 6 && side_length / light_blob_i.length > 0.5);
}
static bool lengthRatioJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
return (light_blob_i.length / light_blob_j.length < 2
&& light_blob_i.length / light_blob_j.length > 0.5);
}
/* 判断两个灯条的错位度,不知道英文是什么!!! */
static bool CuoWeiDuJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
float angle_i = light_blob_i.rect.size.width > light_blob_i.rect.size.height ? light_blob_i.rect.angle :
light_blob_i.rect.angle - 90;
float angle_j = light_blob_j.rect.size.width > light_blob_j.rect.size.height ? light_blob_j.rect.angle :
light_blob_j.rect.angle - 90;
float angle = (angle_i + angle_j) / 2.0 / 180.0 * 3.14159265459;
if (abs(angle_i - angle_j) > 90) {
angle += 3.14159265459 / 2;
}
Vector2f orientation(cos(angle), sin(angle));
Vector2f p2p(light_blob_j.rect.center.x - light_blob_i.rect.center.x,
light_blob_j.rect.center.y - light_blob_i.rect.center.y);
return abs(orientation.dot(p2p)) < 20;
}
static bool boxAngleJudge(const LightBlob &light_blob_i, const LightBlob &light_blob_j) {
float angle_i = light_blob_i.rect.size.width > light_blob_i.rect.size.height ? light_blob_i.rect.angle :
light_blob_i.rect.angle - 90;
float angle_j = light_blob_j.rect.size.width > light_blob_j.rect.size.height ? light_blob_j.rect.angle :
light_blob_j.rect.angle - 90;
float angle = (angle_i + angle_j) / 2.0;
if (abs(angle_i - angle_j) > 90) {
angle += 90.0;
}
return (-120.0 < angle && angle < -60.0) || (60.0 < angle && angle < 120.0);
}
static bool isCoupleLight(const LightBlob &light_blob_i, const LightBlob &light_blob_j, uint8_t enemy_color) {
return light_blob_i.BlobColor == enemy_color &&
light_blob_j.BlobColor == enemy_color &&
lengthRatioJudge(light_blob_i, light_blob_j) &&
lengthJudge(light_blob_i, light_blob_j) &&
// heightJudge(light_blob_i, light_blob_j) &&
angelJudge(light_blob_i, light_blob_j) &&
boxAngleJudge(light_blob_i, light_blob_j) &&
CuoWeiDuJudge(light_blob_i, light_blob_j);
}
static double centerDistance(const cv::Rect2d &box) {
double dx = box.x - box.width / 2 - 320;
double dy = box.y - box.height / 2 - 240;
return dx * dx + dy * dy;
}
bool ArmorFinder::findArmorBoxes(const LightBlobs &light_blobs, std::vector<cv::Rect2d> &armor_boxes) {
for (int i = 0; i < light_blobs.size() - 1; ++i) {
for (int j = i + 1; j < light_blobs.size(); ++j) {
if (!isCoupleLight(light_blobs.at(i), light_blobs.at(j), enemy_color)) {
continue;
}
cv::Rect2d rect_left = light_blobs.at(static_cast<unsigned long>(i)).rect.boundingRect();
cv::Rect2d rect_right = light_blobs.at(static_cast<unsigned long>(j)).rect.boundingRect();
double min_x, min_y, max_x, max_y;
min_x = fmin(rect_left.x, rect_right.x) - 4;
max_x = fmax(rect_left.x + rect_left.width, rect_right.x + rect_right.width) + 4;
min_y = fmin(rect_left.y, rect_right.y) - 0.5 * (rect_left.height + rect_right.height) / 2.0;
max_y = fmax(rect_left.y + rect_left.height, rect_right.y + rect_right.height) +
0.5 * (rect_left.height + rect_right.height) / 2.0;
if (min_x < 0 || max_x > 640 || min_y < 0 || max_y > 480) {
continue;
}
armor_boxes.emplace_back(cv::Rect2d(min_x, min_y, max_x - min_x, max_y - min_y));
}
}
if (armor_boxes.empty()) {
return false;
}
sort(armor_boxes.begin(), armor_boxes.end(), [](cv::Rect2d box1, cv::Rect2d box2) -> bool {
return centerDistance(box1) < centerDistance(box2);
});
return true;
}

View File

@@ -1,133 +0,0 @@
//
// Created by xinyang on 19-7-10.
//
#include <armor_finder/armor_finder.h>
static double lw_rate(const cv::RotatedRect &rect) {
return rect.size.height > rect.size.width ?
rect.size.height / rect.size.width :
rect.size.width / rect.size.height;
}
bool rectangleContainPoint(cv::RotatedRect rectangle, cv::Point2f point) {
//转化为轮廓
cv::Point2f corners[4];
rectangle.points(corners);
cv::Point2f *lastItemPointer = (corners + sizeof corners / sizeof corners[0]);
vector<cv::Point2f> contour(corners, lastItemPointer);
//判断
double indicator = pointPolygonTest(contour, point, true);
return indicator >= 0;
}
// 下面的函数可以有性能优化,暂时未做。
static double nonZeroRateOfRotateRect(const cv::Mat &bin, const cv::RotatedRect &rotrect) {
auto rect = rotrect.boundingRect();
if (rect.x < 0 || rect.y < 0 || rect.x + rect.width > bin.cols || rect.y + rect.height > bin.rows) {
return 0;
}
auto roi = bin(rect);
int cnt = 0;
for (int r = 0; r < roi.rows; r++) {
for (int c = 0; c < roi.cols; c++) {
if (rectangleContainPoint(rotrect, cv::Point(c + rect.x, r + rect.y))) {
if (roi.at<uint8_t>(r, c)) {
cnt++;
}
}
}
}
return double(cnt) / rotrect.size.area();
}
int linePointX(const cv::Point2f &p1, const cv::Point2f &p2, int y) {
return (p2.x - p1.x) / (p2.y - p1.y) * (y - p1.y) + p1.x;
}
// 性能优化后的函数
static double nonZeroRateOfRotateRect_opt(const cv::Mat &bin, const cv::RotatedRect &rotrect) {
int cnt = 0;
cv::Point2f corners[4];
rotrect.points(corners);
sort(corners, &corners[4], [](cv::Point2f p1, cv::Point2f p2) {
return p1.y < p2.y;
});
for (int r = corners[0].y; r < corners[1].y; r++) {
auto start = min(linePointX(corners[0], corners[1], r), linePointX(corners[0], corners[2], r)) - 1;
auto end = max(linePointX(corners[0], corners[1], r), linePointX(corners[0], corners[2], r)) + 1;
if (start < 0 || end > 640) return 0;
for (int c = start; c < end; c++) {
if (bin.at<uint8_t>(r, c)) {
cnt++;
}
}
}
for (int r = corners[1].y; r < corners[2].y; r++) {
auto start = min(linePointX(corners[0], corners[2], r), linePointX(corners[1], corners[3], r)) - 1;
auto end = max(linePointX(corners[0], corners[2], r), linePointX(corners[1], corners[3], r)) + 1;
if (start < 0 || end > 640) return 0;
for (int c = start; c < end; c++) {
if (bin.at<uint8_t>(r, c)) {
cnt++;
}
}
}
for (int r = corners[2].y; r < corners[3].y; r++) {
auto start = min(linePointX(corners[1], corners[3], r), linePointX(corners[2], corners[3], r)) - 1;
auto end = max(linePointX(corners[1], corners[3], r), linePointX(corners[2], corners[3], r)) + 1;
if (start < 0 || end > 640) return 0;
for (int c = start; c < end; c++) {
if (bin.at<uint8_t>(r, c)) {
cnt++;
}
}
}
return double(cnt) / rotrect.size.area();
}
static bool isValidLightBlob(const cv::Mat &bin, const cv::RotatedRect &rect) {
return (lw_rate(rect) > 1.5) &&
// (rect.size.width*rect.size.height < 3000) &&
(rect.size.width * rect.size.height > 1) &&
(nonZeroRateOfRotateRect_opt(bin, rect) > 0.8);
// (nonZeroRateOfRotateRect(bin, rect) > 0.8);
}
void get_blob_color(const cv::Mat &src, std::vector<LightBlob> &blobs) {
for (auto &blob : blobs) {
auto region = blob.rect.boundingRect();
region.x -= fmax(2, region.width * 0.1);
region.y -= fmax(2, region.height * 0.05);
region.width += 2 * fmax(2, region.width * 0.1);
region.height += 2 * fmax(2, region.height * 0.05);
region &= cv::Rect(0, 0, 640, 480);
cv::Mat roi = src(region);
long long int red_cnt = 0, blue_cnt = 0;
for (int row = 0; row < roi.rows; row++) {
for (int col = 0; col < roi.cols; col++) {
red_cnt += roi.at<cv::Vec3b>(row, col)[2];
blue_cnt += roi.at<cv::Vec3b>(row, col)[0];
}
}
if (red_cnt > blue_cnt) {
blob.BlobColor = BLOB_RED;
} else {
blob.BlobColor = BLOB_BLUE;
}
}
}
bool ArmorFinder::findLightBlobs(const cv::Mat &src_bin, LightBlobs &light_blobs) {
std::vector<std::vector<cv::Point> > light_contours;
cv::findContours(src_bin, light_contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
for (auto &light_contour : light_contours) {
cv::RotatedRect rect = cv::minAreaRect(light_contour);
if (isValidLightBlob(src_bin, rect)) {
light_blobs.emplace_back(rect);
}
}
get_blob_color(src_raw, light_blobs);
return light_blobs.size() >= 2;
}

View File

@@ -3,118 +3,15 @@
// //
#include <armor_finder/armor_finder.h> #include <armor_finder/armor_finder.h>
#include <opencv2/highgui.hpp>
#include <show_images/show_images.h> #include <show_images/show_images.h>
#include <options/options.h> #include <options/options.h>
#include <log.h> #include <log.h>
static string prior_blue[] = {
"B8", "B1", "B3", "B4", "B5", "B7", "B2",
"R8", "R1", "R3", "R4", "R5", "R7", "R2",
};
static string prior_red[] = {
"R8", "R1", "R3", "R4", "R5", "R7", "R2",
"B8", "B1", "B3", "B4", "B5", "B7", "B2",
};
void imagePreProcess(cv::Mat &src) {
static cv::Mat kernel_erode = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 5));
erode(src, src, kernel_erode);
static cv::Mat kernel_dilate = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 5));
dilate(src, src, kernel_dilate);
static cv::Mat kernel_dilate2 = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 5));
dilate(src, src, kernel_dilate2);
static cv::Mat kernel_erode2 = getStructuringElement(cv::MORPH_RECT, cv::Size(3, 5));
erode(src, src, kernel_erode2);
float alpha = 1.5;
int beta = 0;
src.convertTo(src, -1, alpha, beta);
}
bool ArmorFinder::stateSearchingTarget(cv::Mat &src) { bool ArmorFinder::stateSearchingTarget(cv::Mat &src) {
std::vector<cv::Mat> channels; // 通道拆分 if(findArmorBox(src, armor_box)){
cv::Mat src_bin, color; // 二值图和颜色通道图 return true;
LightBlobs light_blobs; // 存储所有可能的灯条 }else{
std::vector<cv::Rect2d> armor_boxes; // 装甲板候选区 armor_box = ArmorBox();
std::vector<cv::Rect2d> boxes_number[15]; // 装甲板候选区放置在对应id位置
armor_box = cv::Rect2d(0, 0, 0, 0); // 重置目标装甲板位置
boxid = -1; // 重置目标装甲板id
cv::split(src, channels); /************************/
if (enemy_color == ENEMY_BLUE) /* */
color = channels[0]; /* 根据目标颜色进行通道提取 */
else if (enemy_color == ENEMY_RED) /* */
color = channels[2]; /************************/
cv::threshold(color, src_bin, 170, 255, CV_THRESH_BINARY); // 二值化对应通道
imagePreProcess(src_bin); // 开闭运算
if (!findLightBlobs(src_bin, light_blobs)) {
return false; return false;
} }
if (show_light_blobs) {
showContours("light_blobs", src, light_blobs);
cv::waitKey(1);
}
if (!findArmorBoxes(light_blobs, armor_boxes)) {
return false;
}
if (show_armor_boxes) {
showArmorBoxVector("boxes", src, armor_boxes);
cv::waitKey(1);
}
if (classifier && use_classifier) {
for (auto box : armor_boxes) {
cv::Mat roi = src(box).clone();
cv::resize(roi, roi, cv::Size(48, 36));
int c = classifier(roi);
boxes_number[c].emplace_back(box);
}
if (enemy_color == ENEMY_BLUE) {
for (auto name : prior_blue) {
if (!boxes_number[name2id[name]].empty()) {
armor_box = boxes_number[name2id[name]][0];
boxid = name2id[name];
break;
}
}
} else if (enemy_color == ENEMY_RED) {
for (auto name : prior_red) {
if (!boxes_number[name2id[name]].empty()) {
armor_box = boxes_number[name2id[name]][0];
boxid = name2id[name];
break;
}
}
} else {
LOGE_INFO("enemy_color ERROR!");
}
if (armor_box == cv::Rect2d(0, 0, 0, 0)) {
return false;
}
if (show_armor_boxes) {
showArmorBoxClass("class", src, boxes_number);
}
if (save_labelled_boxes) {
for (int i = 0; i < sizeof(boxes_number) / sizeof(boxes_number[0]); i++) {
for (auto &box : boxes_number[i]) {
char filename[100];
sprintf(filename, PROJECT_DIR"/armor_box_photo/%s_%d.jpg", id2name[i].data(),
time(nullptr) + clock());
cv::imwrite(filename, src(box));
}
}
}
} else {
armor_box = armor_boxes[0];
boxid = -1;
}
return sendBoxPosition();
} }

View File

@@ -3,12 +3,13 @@
// //
#include <armor_finder/armor_finder.h> #include <armor_finder/armor_finder.h>
#include<log.h>
static bool sendTarget(Serial &serial, double x, double y, double z) { static bool sendTarget(Serial &serial, double x, double y, double z, uint16_t shoot_delay) {
static short x_tmp, y_tmp, z_tmp; static short x_tmp, y_tmp, z_tmp;
static time_t last_time = time(nullptr); static time_t last_time = time(nullptr);
static int fps; static int fps;
uint8_t buff[8]; uint8_t buff[10];
time_t t = time(nullptr); time_t t = time(nullptr);
if (last_time != t) { if (last_time != t) {
@@ -29,19 +30,25 @@ static bool sendTarget(Serial &serial, double x, double y, double z) {
buff[4] = static_cast<char>((y_tmp >> 0) & 0xFF); buff[4] = static_cast<char>((y_tmp >> 0) & 0xFF);
buff[5] = static_cast<char>((z_tmp >> 8) & 0xFF); buff[5] = static_cast<char>((z_tmp >> 8) & 0xFF);
buff[6] = static_cast<char>((z_tmp >> 0) & 0xFF); buff[6] = static_cast<char>((z_tmp >> 0) & 0xFF);
buff[7] = 'e'; buff[7] = static_cast<char>((shoot_delay >> 8) & 0xFF);
buff[8] = static_cast<char>((shoot_delay >> 0) & 0xFF);
buff[9] = 'e';
// if(buff[7]<<8 | buff[8])
// cout << (buff[7]<<8 | buff[8]) << endl;
return serial.WriteData(buff, sizeof(buff)); return serial.WriteData(buff, sizeof(buff));
} }
bool ArmorFinder::sendBoxPosition() { bool ArmorFinder::sendBoxPosition(uint16_t shoot_delay) {
if(armor_box.rect == cv::Rect2d()) return false; if(armor_box.rect == cv::Rect2d()) return false;
auto rect = armor_box; if(shoot_delay){
LOGM(STR_CTR(WORD_BLUE, "shoot after %dms"), shoot_delay);
}
auto rect = armor_box.rect;
double dx = rect.x + rect.width / 2 - 320; double dx = rect.x + rect.width / 2 - 320;
double dy = rect.y + rect.height / 2 - 240 - 20; double dy = rect.y + rect.height / 2 - 240 - 20;
double yaw = atan(dx / FOCUS_PIXAL) * 180 / PI; double yaw = atan(dx / FOCUS_PIXAL) * 180 / PI;
double pitch = atan(dy / FOCUS_PIXAL) * 180 / PI; double pitch = atan(dy / FOCUS_PIXAL) * 180 / PI;
double dist = DISTANCE_HEIGHT / rect.height; double dist = DISTANCE_HEIGHT / rect.height;
// cout << yaw << endl; // cout << yaw << endl;
return sendTarget(serial, yaw, -pitch, dist); return sendTarget(serial, yaw, -pitch, dist, shoot_delay);
} }

View File

@@ -2,30 +2,76 @@
// Created by xinyang on 19-3-27. // Created by xinyang on 19-3-27.
// //
#include <log.h> #include <log.h>
#include <options/options.h>
#include <armor_finder/armor_finder.h> #include <armor_finder/armor_finder.h>
#include <show_images/show_images.h>
bool ArmorFinder::stateTrackingTarget(cv::Mat &src) { bool ArmorFinder::stateTrackingTarget(cv::Mat &src) {
if(!tracker->update(src, armor_box)){ auto pos = armor_box.rect;
if(!tracker->update(src, pos)){
armor_box = ArmorBox();
return false; return false;
} }
if((armor_box & cv::Rect2d(0, 0, 640, 480)) != armor_box){ if((pos & cv::Rect2d(0, 0, 640, 480)) != pos){
armor_box = ArmorBox();
return false; return false;
} }
cv::Mat roi = src.clone()(armor_box); cv::Rect2d bigger_rect;
if(classifier){
cv::resize(roi, roi, cv::Size(48, 36)); bigger_rect.x = pos.x - pos.width / 2.0;
if(classifier(roi) == 0){ bigger_rect.y = pos.y - pos.height / 2.0;
return false; bigger_rect.height = pos.height * 2;
bigger_rect.width = pos.width * 2;
bigger_rect &= cv::Rect2d(0, 0, 640, 480);
if(show_armor_box)
showTrackSearchingPos("track", src, bigger_rect);
cv::Mat roi = src(bigger_rect).clone();
ArmorBox box;
if(findArmorBox(roi, box)) {
armor_box = box;
armor_box.rect.x += bigger_rect.x;
armor_box.rect.y += bigger_rect.y;
for(auto &blob : armor_box.light_blobs){
blob.rect.center.x += bigger_rect.x;
blob.rect.center.y += bigger_rect.y;
} }
}else{ }else{
cv::Mat roi_gray; roi = src(pos).clone();
cv::cvtColor(roi, roi_gray, CV_RGB2GRAY); if(classifier){
cv::threshold(roi_gray, roi_gray, 180, 255, cv::THRESH_BINARY); cv::resize(roi, roi, cv::Size(48, 36));
contour_area = cv::countNonZero(roi_gray); if(classifier(roi) == 0){
if(abs(cv::countNonZero(roi_gray) - contour_area) > contour_area * 0.3){ armor_box = ArmorBox();
return false; return false;
}
}else{
cv::Mat roi_gray;
cv::cvtColor(roi, roi_gray, CV_RGB2GRAY);
cv::threshold(roi_gray, roi_gray, 180, 255, cv::THRESH_BINARY);
contour_area = cv::countNonZero(roi_gray);
if(abs(cv::countNonZero(roi_gray) - contour_area) > contour_area * 0.3){
armor_box = ArmorBox();
return false;
}
} }
armor_box.rect = pos;
armor_box.light_blobs.clear();
} }
return sendBoxPosition();
// armor_box.x -= armor_box.width / 4.0;
// armor_box.y -= armor_box.height / 4.0;
// armor_box.height *= 1.5;
// armor_box.width *= 1.5;
// roi = src(armor_box);
// if(findSearchingTarget(roi)){
//
// }
// sendBoxPosition();
return true;
} }

View File

@@ -1,13 +1,30 @@
#include <show_images/show_images.h> #include <show_images/show_images.h>
#include <opencv2/highgui.hpp> #include <opencv2/highgui.hpp>
#include <options/options.h>
#include <log.h> #include <log.h>
using namespace cv; using namespace cv;
void drawLightBlobs(cv::Mat &src, const LightBlobs &blobs){
for (const auto &blob:blobs) {
Scalar color(0,255,0);
if (blob.blob_color == BLOB_RED)
color = Scalar(0, 0, 255);
else if (blob.blob_color == BLOB_BLUE)
color = Scalar(255, 0, 0);
cv::Point2f vertices[4];
blob.rect.points(vertices);
for (int j = 0; j < 4; j++) {
cv::line(src, vertices[j], vertices[(j + 1) % 4], color, 2);
}
}
}
/************************** /**************************
* 显示多个装甲板区域 * * 显示多个装甲板区域 *
**************************/ **************************/
void showArmorBoxVector(std::string windows_name, const cv::Mat &src, const std::vector<cv::Rect2d> &armor_box) { void showArmorBoxes(std::string windows_name, const cv::Mat &src, const ArmorBoxes &armor_boxes) {
static Mat image2show; static Mat image2show;
if (src.type() == CV_8UC1) {// 黑白图像 if (src.type() == CV_8UC1) {// 黑白图像
cvtColor(src, image2show, COLOR_GRAY2RGB); cvtColor(src, image2show, COLOR_GRAY2RGB);
@@ -15,8 +32,15 @@ void showArmorBoxVector(std::string windows_name, const cv::Mat &src, const std:
image2show = src.clone(); image2show = src.clone();
} }
for (auto &box:armor_box) { for (auto &box:armor_boxes) {
rectangle(image2show, box, Scalar(0, 255, 0), 1); if(box.box_color == BOX_BLUE) {
rectangle(image2show, box.rect, Scalar(0, 255, 0), 1);
drawLightBlobs(image2show, box.light_blobs);
}else if(box.box_color == BOX_RED){
rectangle(image2show, box.rect, Scalar(0, 255, 0), 1);
drawLightBlobs(image2show, box.light_blobs);
}
} }
imshow(windows_name, image2show); imshow(windows_name, image2show);
} }
@@ -24,25 +48,26 @@ void showArmorBoxVector(std::string windows_name, const cv::Mat &src, const std:
/************************** /**************************
* 显示多个装甲板区域及其类别 * * 显示多个装甲板区域及其类别 *
**************************/ **************************/
void showArmorBoxClass(std::string window_names, const cv::Mat &src, vector<cv::Rect2d> boxes[10]) { void showArmorBoxesClass(std::string window_names, const cv::Mat &src, const ArmorBoxes boxes[15]) {
static Mat image2show; static Mat image2show;
if (src.type() == CV_8UC1) { // 黑白图像 if (src.type() == CV_8UC1) { // 黑白图像
cvtColor(src, image2show, COLOR_GRAY2RGB); cvtColor(src, image2show, COLOR_GRAY2RGB);
} else if (src.type() == CV_8UC3) { //RGB 彩色 } else if (src.type() == CV_8UC3) { //RGB 彩色
image2show = src.clone(); image2show = src.clone();
} }
for (int i = 0; i < 14; i++) { for (int i = 1; i < 15; i++) {
if (!boxes[i].empty()) { if (!boxes[i].empty()) {
for (auto box : boxes[i]) { for (auto box : boxes[i]) {
rectangle(image2show, box, Scalar(0, 255, 0), 1); rectangle(image2show, box.rect, Scalar(0, 255, 0), 1);
drawLightBlobs(image2show, box.light_blobs);
if (i == -1) if (i == -1)
putText(image2show, id2name[i], Point(box.x + 2, box.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1, putText(image2show, id2name[i], Point(box.rect.x + 2, box.rect.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1,
Scalar(0, 255, 0)); Scalar(0, 255, 0));
else if (1 <= i && i < 8) else if (1 <= i && i < 8)
putText(image2show, id2name[i], Point(box.x + 2, box.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1, putText(image2show, id2name[i], Point(box.rect.x + 2, box.rect.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1,
Scalar(255, 0, 0)); Scalar(255, 0, 0));
else if (8 <= i && i < 15) else if (8 <= i && i < 15)
putText(image2show, id2name[i], Point(box.x + 2, box.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1, putText(image2show, id2name[i], Point(box.rect.x + 2, box.rect.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1,
Scalar(0, 0, 255)); Scalar(0, 0, 255));
else if (i != 0) else if (i != 0)
LOGE_INFO("Invalid box id:%d!", i); LOGE_INFO("Invalid box id:%d!", i);
@@ -55,34 +80,48 @@ void showArmorBoxClass(std::string window_names, const cv::Mat &src, vector<cv::
/************************** /**************************
* 显示单个装甲板区域及其类别 * * 显示单个装甲板区域及其类别 *
**************************/ **************************/
void showArmorBox(std::string windows_name, const cv::Mat &src, cv::Rect2d armor_box, int boxid) { void showArmorBox(std::string windows_name, const cv::Mat &src, const ArmorBox &box) {
static Mat image2show; static Mat image2show;
if(box.rect == cv::Rect2d()){
imshow(windows_name, src);
}
if (src.type() == CV_8UC1) { // 黑白图像 if (src.type() == CV_8UC1) { // 黑白图像
cvtColor(src, image2show, COLOR_GRAY2RGB); cvtColor(src, image2show, COLOR_GRAY2RGB);
} else if (src.type() == CV_8UC3) { //RGB 彩色 } else if (src.type() == CV_8UC3) { //RGB 彩色
image2show = src.clone(); image2show = src.clone();
} }
rectangle(image2show, armor_box, Scalar(0, 255, 0), 1); drawLightBlobs(image2show, box.light_blobs);
// static FILE *fp = fopen(PROJECT_DIR"/ratio.txt", "w");
// if(box.light_blobs.size() == 2)
// fprintf(fp, "%lf %lf %lf\n", box.light_blobs[0].length, box.light_blobs[1].length, box.blobsDistance())
// cout << box.lengthDistanceRatio() << endl;
if(box.getOrientation() == ArmorBox::FRONT){
rectangle(image2show, box.rect, Scalar(0, 255, 0), 3);
}else{
rectangle(image2show, box.rect, Scalar(0, 255, 0), 1);
};
char dist[5]; char dist[5];
// sprintf(dist, "%.1f", distance); sprintf(dist, "%.1f", box.getDistance());
if (boxid == -1) if (box.id == -1)
putText(image2show, id2name[boxid]+" "+dist, Point(armor_box.x + 2, armor_box.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1, putText(image2show, id2name[box.id]+" "+dist, Point(box.rect.x + 2, box.rect.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1,
Scalar(0, 255, 0)); Scalar(0, 255, 0));
else if (1 <= boxid && boxid < 8) else if (1 <= box.id && box.id < 8)
putText(image2show, id2name[boxid]+" "+dist, Point(armor_box.x + 2, armor_box.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1, putText(image2show, id2name[box.id]+" "+dist, Point(box.rect.x + 2, box.rect.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1,
Scalar(255, 0, 0)); Scalar(255, 0, 0));
else if (8 <= boxid && boxid < 15) else if (8 <= box.id && box.id < 15)
putText(image2show, id2name[boxid]+" "+dist, Point(armor_box.x + 2, armor_box.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1, putText(image2show, id2name[box.id]+" "+dist, Point(box.rect.x + 2, box.rect.y + 2), cv::FONT_HERSHEY_TRIPLEX, 1,
Scalar(0, 0, 255)); Scalar(0, 0, 255));
else if (boxid != 0) else if (box.id != 0)
LOGE_INFO("Invalid box id:%d!", boxid); LOGE_INFO("Invalid box id:%d!", box.id);
imshow(windows_name, image2show); imshow(windows_name, image2show);
} }
/************************** /**************************
* 显示多个灯条区域 * * 显示多个灯条区域 *
**************************/ **************************/
void showContours(std::string windows_name, const cv::Mat &src, const std::vector<LightBlob> &light_blobs) { void showLightBlobs(std::string windows_name, const cv::Mat &src, const LightBlobs &light_blobs) {
static Mat image2show; static Mat image2show;
if (src.type() == CV_8UC1) { // 黑白图像 if (src.type() == CV_8UC1) { // 黑白图像
@@ -92,13 +131,11 @@ void showContours(std::string windows_name, const cv::Mat &src, const std::vecto
} }
for (const auto &light_blob:light_blobs) { for (const auto &light_blob:light_blobs) {
Scalar color; Scalar color(0, 255, 0);
if (light_blob.BlobColor == BLOB_RED) if (light_blob.blob_color == BLOB_RED)
color = Scalar(0, 0, 255); color = Scalar(0, 0, 255);
else if (light_blob.BlobColor == BLOB_BLUE) else if (light_blob.blob_color == BLOB_BLUE)
color = Scalar(255, 0, 0); color = Scalar(255, 0, 0);
else
color = Scalar(0, 255, 0);
cv::Point2f vertices[4]; cv::Point2f vertices[4];
light_blob.rect.points(vertices); light_blob.rect.points(vertices);
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
@@ -107,3 +144,15 @@ void showContours(std::string windows_name, const cv::Mat &src, const std::vecto
} }
imshow(windows_name, image2show); imshow(windows_name, image2show);
} }
void showTrackSearchingPos(std::string window_names, const cv::Mat &src, const cv::Rect2d pos){
static Mat image2show;
if (src.type() == CV_8UC1) { // 黑白图像
cvtColor(src, image2show, COLOR_GRAY2RGB);
} else if (src.type() == CV_8UC3) { //RGB 彩色
image2show = src.clone();
}
rectangle(image2show, pos, Scalar(0, 255, 0), 1);
imshow(window_names, image2show);
}

View File

@@ -11,7 +11,8 @@ const int SRC_WIDTH = 320;
const int SRC_HEIGHT = 240; const int SRC_HEIGHT = 240;
const int CLOCKWISE = 1; const int CLOCKWISE = 1;
const int ANTICLOCKWISE = -1; const int ANTICLOCKWISE = -1;
const float ATTACK_DISTANCE = 718.0;//cm //const float ATTACK_DISTANCE = 718.0;//cm
const float ATTACK_DISTANCE = 750.0;//cm
const double ARMOR_CENTER_TO_CYCLE_CENTER = 75.0;//cm const double ARMOR_CENTER_TO_CYCLE_CENTER = 75.0;//cm

View File

@@ -27,11 +27,14 @@ public:
Energy(Serial &u, uint8_t &color);//构造函数,参数为串口和敌方颜色 Energy(Serial &u, uint8_t &color);//构造函数,参数为串口和敌方颜色
~Energy();//默认析构函数 ~Energy();//默认析构函数
void run(cv::Mat &gimbal_src, cv::Mat &chassis_src); void runBig(cv::Mat &gimbal_src, cv::Mat &chassis_src);
void run(cv::Mat &gimbal_src); void runBig(cv::Mat &gimbal_src);
void runSmall(cv::Mat &gimbal_src);
Serial &serial;//串口 Serial &serial;//串口
void setEnergyInit();//设置能量机关初始化 void setEnergyInit();//设置能量机关初始化
void setBigEnergyInit();//设置大能量机关初始化
void setSmallEnergyInit();//设置小能量机关初始化
void sendTarget(Serial &serial, float x, float y, float z); void sendTarget(Serial &serial, float x, float y, float z);
@@ -51,7 +54,6 @@ private:
bool energy_rotation_init;//若仍在判断风车旋转方向则为true bool energy_rotation_init;//若仍在判断风车旋转方向则为true
bool manual_mark;//若操作手进行过手动标定则为true bool manual_mark;//若操作手进行过手动标定则为true
bool auto_mark;//云台完成自动对心则置为true bool auto_mark;//云台完成自动对心则置为true
bool shoot;//若为true则要求主控板发弹
bool start_guess;//进入猜测状态的标志 bool start_guess;//进入猜测状态的标志
bool change_target;//目标切换的标志 bool change_target;//目标切换的标志
@@ -77,6 +79,8 @@ private:
float center_delta_yaw, center_delta_pitch;//对心时相差的角度 float center_delta_yaw, center_delta_pitch;//对心时相差的角度
float yaw_rotation, pitch_rotation;//云台yaw轴和pitch轴应该转到的角度 float yaw_rotation, pitch_rotation;//云台yaw轴和pitch轴应该转到的角度
float origin_yaw, origin_pitch;//初始的云台角度设定值 float origin_yaw, origin_pitch;//初始的云台角度设定值
float shoot;//若为2则要求主控板发弹
float sum_yaw, sum_pitch;//yaw和pitch的累计误差即PID中积分项
timeval time_start_guess; timeval time_start_guess;
@@ -158,8 +162,9 @@ private:
void getAllTargetArmorCenters();//记录所有目标装甲板中心坐标 void getAllTargetArmorCenters();//记录所有目标装甲板中心坐标
void getRecentTargetArmorCenters();//记录近30帧目标装甲板中心坐标 void getRecentTargetArmorCenters();//记录近30帧目标装甲板中心坐标
void judgeShoot();//判断是否可以发弹 void judgeMode();//判断大符还是小符
void JudgeMode();//判断大符还是小符 void judgeShootInGimbal();//在云台坐标系中判断是否可以发弹
void judgeShootInWorld();//在世界坐标系中判断是否可以发弹
bool isGuessingTimeout();//判断猜测模式是否超时(没打中) bool isGuessingTimeout();//判断猜测模式是否超时(没打中)
void splitBayerBG(cv::Mat src, cv::Mat &blue, cv::Mat &red);//拜耳阵列分离 void splitBayerBG(cv::Mat src, cv::Mat &blue, cv::Mat &red);//拜耳阵列分离

View File

@@ -61,3 +61,4 @@ void Energy::circleLeastFit()
// cout << "The cycle center is: " << cycle_center << endl; // cout << "The cycle center is: " << cycle_center << endl;
// cout << "The radius is: " << radius << endl; // cout << "The radius is: " << radius << endl;
} }

View File

@@ -125,7 +125,7 @@ void Energy::FlowStripStruct(cv::Mat &src) {
// 此函数对图像进行腐蚀与膨胀操作 // 此函数对图像进行腐蚀与膨胀操作
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
void Energy::CenterRStruct(cv::Mat &src) { void Energy::CenterRStruct(cv::Mat &src) {
Mat element_dilate_1 = getStructuringElement(MORPH_RECT, Size(8, 6)); Mat element_dilate_1 = getStructuringElement(MORPH_RECT, Size(4, 4));
Mat element_erode_1 = getStructuringElement(MORPH_RECT, Size(2, 1)); Mat element_erode_1 = getStructuringElement(MORPH_RECT, Size(2, 1));
Mat element_dilate_2 = getStructuringElement(MORPH_RECT, Size(3, 3)); Mat element_dilate_2 = getStructuringElement(MORPH_RECT, Size(3, 3));
Mat element_erode_2 = getStructuringElement(MORPH_RECT, Size(4 , 4)); Mat element_erode_2 = getStructuringElement(MORPH_RECT, Size(4 , 4));
@@ -134,8 +134,8 @@ void Energy::CenterRStruct(cv::Mat &src) {
// imshow("erode_1", src); // imshow("erode_1", src);
dilate(src, src, element_dilate_1); dilate(src, src, element_dilate_1);
// imshow("dilate_1", src); // imshow("dilate_1", src);
dilate(src, src, element_dilate_2); // dilate(src, src, element_dilate_2);
// imshow("dilate_2", src); // imshow("dilate_2", src);
erode(src,src, element_erode_2); // erode(src,src, element_erode_2);
// imshow("erode_2", src); // imshow("erode_2", src);
} }

View File

@@ -18,7 +18,6 @@ void Energy::clearAll(){
} }
//---------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------
// 此函数用于图像预处理 // 此函数用于图像预处理
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------

View File

@@ -21,7 +21,6 @@ void Energy::initEnergy() {
energy_rotation_init = true; energy_rotation_init = true;
manual_mark = false; manual_mark = false;
auto_mark = false; auto_mark = false;
shoot = false;
start_guess = false; start_guess = false;
change_target = false; change_target = false;
@@ -41,14 +40,15 @@ void Energy::initEnergy() {
last_target_polar_angle = -1000; last_target_polar_angle = -1000;
guess_polar_angle = -1000; guess_polar_angle = -1000;
last_base_angle = -1000; last_base_angle = -1000;
predict_rad = 20; predict_rad = 25;
attack_distance = ATTACK_DISTANCE; attack_distance = ATTACK_DISTANCE;
center_delta_yaw = 1000; center_delta_yaw = 1000;
center_delta_pitch = 1000; center_delta_pitch = 1000;
yaw_rotation = 0; yaw_rotation = 0;
pitch_rotation = 0; pitch_rotation = 0;
origin_yaw = 0; shoot = 0;
origin_pitch = 0; sum_yaw = 0;
sum_pitch = 0;
circle_center_point = Point(0, 0); circle_center_point = Point(0, 0);
target_point = Point(0, 0); target_point = Point(0, 0);
@@ -69,7 +69,7 @@ void Energy::initEnergy() {
// 此函数对能量机关参数进行初始化 // 此函数对能量机关参数进行初始化
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
void Energy::initEnergyPartParam() { void Energy::initEnergyPartParam() {
gimbal_energy_part_param_.GRAY_THRESH = 120;//home gimbal_energy_part_param_.GRAY_THRESH = 140;//home
// gimbal_energy_part_param_.GRAY_THRESH = 200;//official // gimbal_energy_part_param_.GRAY_THRESH = 200;//official
// gimbal_energy_part_param_.GRAY_THRESH = 225; // gimbal_energy_part_param_.GRAY_THRESH = 225;
gimbal_energy_part_param_.SPLIT_GRAY_THRESH = 230; gimbal_energy_part_param_.SPLIT_GRAY_THRESH = 230;
@@ -81,7 +81,7 @@ void Energy::initEnergyPartParam() {
gimbal_energy_part_param_.FAN_CONTOUR_LENGTH_MIN = 80; gimbal_energy_part_param_.FAN_CONTOUR_LENGTH_MIN = 80;
gimbal_energy_part_param_.FAN_CONTOUR_LENGTH_MAX = 100; gimbal_energy_part_param_.FAN_CONTOUR_LENGTH_MAX = 100;
gimbal_energy_part_param_.FAN_CONTOUR_WIDTH_MIN = 20; gimbal_energy_part_param_.FAN_CONTOUR_WIDTH_MIN = 20;
gimbal_energy_part_param_.FAN_CONTOUR_WIDTH_MAX = 50; 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_MAX = 4;
gimbal_energy_part_param_.FAN_CONTOUR_HW_RATIO_MIN = 1; 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_AREA_RATIO_MIN = 0.65;
@@ -107,20 +107,20 @@ void Energy::initEnergyPartParam() {
gimbal_energy_part_param_.CENTER_R_CONTOUR_WIDTH_MAX = 25; gimbal_energy_part_param_.CENTER_R_CONTOUR_WIDTH_MAX = 25;
gimbal_energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MAX = 3; gimbal_energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MAX = 3;
gimbal_energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MIN = 1; gimbal_energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MIN = 1;
gimbal_energy_part_param_.CENTER_R_CONTOUR_AREA_RATIO_MIN = 0.7; gimbal_energy_part_param_.CENTER_R_CONTOUR_AREA_RATIO_MIN = 0.5;
gimbal_energy_part_param_.CENTER_R_CONTOUR_INTERSETION_AREA_MIN = 10; gimbal_energy_part_param_.CENTER_R_CONTOUR_INTERSETION_AREA_MIN = 10;
gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MAX = 17000; gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MAX = 3000;
gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MIN = 0; gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MIN = 1000;
gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MIN = 60; 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_LENGTH_MAX = 100;
gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MIN = 20; 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_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_MAX = 3;
gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MIN = 1; gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MIN = 1;
gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MAX = 0.62; gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MAX = 0.65;
gimbal_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MIN = 0.34; 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.58; gimbal_energy_part_param_.FLOW_STRIP_FAN_NON_ZERO_RATE_MAX = 0.65;
gimbal_energy_part_param_.FLOW_STRIP_FAN_NON_ZERO_RATE_MIN = 0.34; 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_MAX = 0.2;
// gimbal_energy_part_param_.FLOW_STRIP_FAN_NON_ZERO_RATE_MIN = 0.08; // gimbal_energy_part_param_.FLOW_STRIP_FAN_NON_ZERO_RATE_MIN = 0.08;
@@ -130,19 +130,19 @@ void Energy::initEnergyPartParam() {
gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MIN = 38; 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_LENGTH_MAX = 60;
gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MIN = 8; gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MIN = 8;
gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX = 28; 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_MAX = 12;
// gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN = 4; // gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN = 4;
gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN = 2.3; 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_RATIO_MIN = 0.5;
gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_INTERSETION_AREA_MIN = 117; gimbal_energy_part_param_.FLOW_STRIP_CONTOUR_INTERSETION_AREA_MIN = 100;
gimbal_energy_part_param_.TWIN_ANGEL_MAX = 10; gimbal_energy_part_param_.TWIN_ANGEL_MAX = 10;
gimbal_energy_part_param_.TARGET_INTERSETION_CONTOUR_AREA_MIN = 40; gimbal_energy_part_param_.TARGET_INTERSETION_CONTOUR_AREA_MIN = 40;
chassis_energy_part_param_.GRAY_THRESH = 120;//home_small
chassis_energy_part_param_.GRAY_THRESH = 230;//home_big chassis_energy_part_param_.GRAY_THRESH = 120;//home
// chassis_energy_part_param_.GRAY_THRESH = 200;//official // chassis_energy_part_param_.GRAY_THRESH = 200;//official
// chassis_energy_part_param_.GRAY_THRESH = 225; // chassis_energy_part_param_.GRAY_THRESH = 225;
chassis_energy_part_param_.SPLIT_GRAY_THRESH = 230; chassis_energy_part_param_.SPLIT_GRAY_THRESH = 230;
@@ -189,7 +189,7 @@ void Energy::initEnergyPartParam() {
chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MIN = 90; chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MIN = 90;
chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MAX = 140; chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MAX = 140;
chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MIN = 35; chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MIN = 35;
chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MAX = 60; chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MAX = 65;
chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MAX = 3; chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MAX = 3;
chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MIN = 1; chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MIN = 1;
chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MAX = 0.55; chassis_energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MAX = 0.55;
@@ -231,11 +231,11 @@ void Energy::initRotation() {
else if (target_polar_angle > last_target_polar_angle) anticlockwise_rotation_init_cnt++; else if (target_polar_angle > last_target_polar_angle) anticlockwise_rotation_init_cnt++;
} }
//由于刚开始圆心判断不准,角度变化可能计算有误,因此需要在角度正向或逆向变化足够大时才可确定是否为顺逆时针 //由于刚开始圆心判断不准,角度变化可能计算有误,因此需要在角度正向或逆向变化足够大时才可确定是否为顺逆时针
if (clockwise_rotation_init_cnt == 30) { if (clockwise_rotation_init_cnt == 15) {
energy_rotation_direction = CLOCKWISE;//顺时针变化30次确定为顺时针 energy_rotation_direction = CLOCKWISE;//顺时针变化30次确定为顺时针
cout << "rotation: " << energy_rotation_direction << endl; cout << "rotation: " << energy_rotation_direction << endl;
energy_rotation_init = false; energy_rotation_init = false;
} else if (anticlockwise_rotation_init_cnt == 30) { } else if (anticlockwise_rotation_init_cnt == 15) {
energy_rotation_direction = ANTICLOCKWISE;//逆时针变化30次确定为顺时针 energy_rotation_direction = ANTICLOCKWISE;//逆时针变化30次确定为顺时针
cout << "rotation: " << energy_rotation_direction << endl; cout << "rotation: " << energy_rotation_direction << endl;
energy_rotation_init = false; energy_rotation_init = false;

View File

@@ -45,3 +45,32 @@ void Energy::setEnergyInit() {
is_gimbal = true; is_gimbal = true;
is_chassis = false; is_chassis = false;
} }
//----------------------------------------------------------------------------------------------------------------------
// 此函数为大能量机关再初始化函数
// ---------------------------------------------------------------------------------------------------------------------
void Energy::setBigEnergyInit() {
initEnergy();
initEnergyPartParam();
is_big = true;
is_small = false;
is_gimbal = true;
is_chassis = false;
}
//----------------------------------------------------------------------------------------------------------------------
// 此函数为大能量机关再初始化函数
// ---------------------------------------------------------------------------------------------------------------------
void Energy::setSmallEnergyInit() {
initEnergy();
initEnergyPartParam();
is_big = false;
is_small = true;
is_gimbal = true;
is_chassis = false;
}

View File

@@ -69,6 +69,7 @@ int Energy::findArmors(const cv::Mat src) {
ArmorStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找 ArmorStruct(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);
imshow("armor struct", src_bin);
// findContours(src_bin, armor_contours_external, CV_RETR_EXTERNAL, 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++)//去除外轮廓 // for (int i = 0; i < armor_contours_external.size(); i++)//去除外轮廓
@@ -132,7 +133,7 @@ bool Energy::findCenterR(const cv::Mat src) {
circle_center_point = centerR.center; circle_center_point = centerR.center;
circle_center_point.y += target_length / 7.5;//实际最小二乘得到的中心在R的下方 circle_center_point.y += target_length / 7.5;//实际最小二乘得到的中心在R的下方
// RotatedRect cur_rect = minAreaRect(center_R_contour); RotatedRect cur_rect = minAreaRect(center_R_contour);
// Size2f cur_size = cur_rect.size; // Size2f cur_size = cur_rect.size;
// float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width; // 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; // float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width;
@@ -147,10 +148,11 @@ bool Energy::findCenterR(const cv::Mat src) {
// cout << "R intersection: " << contourArea(intersection) << endl; // cout << "R intersection: " << contourArea(intersection) << endl;
// return true; // return true;
// } // }
// cout << cur_rect.center << endl;
return true; return true;
} }
cout << "find center R false!" << endl; cout << "find center R false!" << endl;
// cv::waitKey(0);
return false; return false;
} }
@@ -159,7 +161,7 @@ bool Energy::findCenterR(const cv::Mat src) {
//---------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------
// 此函数用于判断找到的矩形候选区是否为含流动条的扇叶 // 此函数用于判断找到的矩形候选区是否为含流动条的扇叶
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
bool Energy:: findFlowStripFan(const cv::Mat src) { bool Energy::findFlowStripFan(const cv::Mat src) {
if (src.empty())return false; if (src.empty())return false;
static Mat src_bin; static Mat src_bin;
static Mat src_copy; static Mat src_copy;
@@ -170,25 +172,14 @@ bool Energy:: findFlowStripFan(const cv::Mat src) {
} }
std::vector<vector<Point> > flow_strip_fan_contours; std::vector<vector<Point> > flow_strip_fan_contours;
FlowStripFanStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找 FlowStripFanStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找
// imshow("flow strip fan struct", src_bin); imshow("flow strip fan struct", src_bin);
// vector<vector<Point>> contours;
// 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(contourArea(flow_strip_fan_contour)>1800&&contourArea(flow_strip_fan_contour)<2300)
// contours.push_back(flow_strip_fan_contour);
//// cout<<contourArea(flow_strip_fan_contour)<<endl;
// }
// Mat draw(src.size(),CV_8UC3,Scalar(0,0,0));
// drawContours(draw,contours,-1,Scalar(255,255,255),1);
// imshow("draw",draw);
// waitKey();
findContours(src_bin, flow_strip_fan_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); findContours(src_bin, flow_strip_fan_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
for (auto &flow_strip_fan_contour : flow_strip_fan_contours) { for (auto &flow_strip_fan_contour : flow_strip_fan_contours) {
if (!isValidFlowStripFanContour(src_bin, flow_strip_fan_contour)) { if (!isValidFlowStripFanContour(src_bin, flow_strip_fan_contour)) {
continue; continue;
} }
// cout<<contourArea(flow_strip_fan_contour)<<endl;
flow_strip_fan = cv::minAreaRect(flow_strip_fan_contour); flow_strip_fan = cv::minAreaRect(flow_strip_fan_contour);
// RotatedRect cur_rect = minAreaRect(flow_strip_fan_contour); // RotatedRect cur_rect = minAreaRect(flow_strip_fan_contour);
@@ -204,12 +195,12 @@ bool Energy:: findFlowStripFan(const cv::Mat src) {
// cout << "non zero: " << non_zero_rate << endl; // cout << "non zero: " << non_zero_rate << endl;
// cout<<cur_contour_area / cur_size.area()<<endl; // cout<<cur_contour_area / cur_size.area()<<endl;
// } // }
// cout << cur_rect.center << endl;
return true; return true;
} }
// showFlowStripFan("strip fan", src_bin); // showFlowStripFan("strip fan", src_bin);
cout << "flow strip fan false!" << endl; cout << "flow strip fan false!" << endl;
// waitKey(); // waitKey(0);
return false; return false;
} }
@@ -234,21 +225,21 @@ bool Energy::findFlowStrip(const cv::Mat src) {
if (!isValidFlowStripContour(flow_strip_contour)) { if (!isValidFlowStripContour(flow_strip_contour)) {
continue; continue;
} }
// cout<<"size: "<<contourArea(flow_strip_contour)<<endl;
flow_strip = cv::minAreaRect(flow_strip_contour); flow_strip = cv::minAreaRect(flow_strip_contour);
// RotatedRect cur_rect = minAreaRect(flow_strip_contour); // RotatedRect cur_rect = minAreaRect(flow_strip_contour);
// Size2f cur_size = cur_rect.size; // Size2f cur_size = cur_rect.size;
// float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width; // 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; // float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width;
// if (length / width > 4 && width > 7 && width<30) { // if (length / width > 2.5 && width > 7 && width<40) {
// cout << cur_rect.center << endl; // cout << cur_rect.center << endl;
// flow_strip = cv::minAreaRect(flow_strip_contour); // flow_strip = cv::minAreaRect(flow_strip_contour);
// cout << "flow strip area: " << length << '\t' << width << endl; // cout << "flow strip area: " << length << '\t' << width << endl;
// } // }
// cout << cur_rect.center << endl;
return true; return true;
} }
cout << "flow strip false!" << endl; cout << "flow strip false!" << endl;
// waitKey(); // waitKey(0);
return false; return false;
} }
@@ -265,7 +256,7 @@ bool Energy::findCenterROI(const cv::Mat src) {
vector<Point2f> mask_rect; vector<Point2f> mask_rect;
target_armor.points(vertices); //计算矩形的4个顶点 target_armor.points(vertices); //计算矩形的4个顶点
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
line(src_mask, vertices[i], vertices[(i + 1) % 4], Scalar(0, 0, 0), 15); line(src_mask, vertices[i], vertices[(i + 1) % 4], Scalar(0, 0, 0), 20);
// imshow("fill", src_mask); // imshow("fill", src_mask);
if (!findFlowStrip(src_mask))return false; if (!findFlowStrip(src_mask))return false;
float length = target_armor.size.height > target_armor.size.width ? float length = target_armor.size.height > target_armor.size.width ?

View File

@@ -4,6 +4,7 @@
#include "energy/energy.h" #include "energy/energy.h"
#include "energy/constant.h" #include "energy/constant.h"
#include "config/setconfig.h"
using namespace std; using namespace std;
using namespace cv; using namespace cv;
@@ -12,8 +13,13 @@ using namespace cv;
// 此函数通过自瞄逻辑击打目标点,用于大符的自动对心和小符直接打击 // 此函数通过自瞄逻辑击打目标点,用于大符的自动对心和小符直接打击
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
void Energy::getAimPoint(cv::Point target_point) { void Energy::getAimPoint(cv::Point target_point) {
double dx = -(target_point.x - 320 - 10); //五号车
double dy = -(target_point.y - 240 - 22); // double dx = -(target_point.x - 320 - 10);
// double dy = -(target_point.y - 240 - 22);
//四号车
double dx = -(target_point.x - 320 - COMPENSATE_YAW);
double dy = -(target_point.y - 240 - COMPENSATE_PITCH);
yaw_rotation = atan(dx / FOCUS_PIXAL) * 180 / PI; yaw_rotation = atan(dx / FOCUS_PIXAL) * 180 / PI;
pitch_rotation = atan(dy / FOCUS_PIXAL) * 180 / PI; pitch_rotation = atan(dy / FOCUS_PIXAL) * 180 / PI;
// cout << "yaw: " << yaw_rotation << '\t' << "pitch: " << pitch_rotation << endl;
} }

View File

@@ -13,18 +13,24 @@ using namespace cv;
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
bool Energy::getOrigin() { bool Energy::getOrigin() {
if (!auto_mark && !manual_mark) { if (!auto_mark && !manual_mark) {
double dx = -(circle_center_point.x - 320); //五号车
double dy = -(circle_center_point.y - 240); // double dx = -(circle_center_point.x - 320 - 10);
center_delta_yaw = atan(dx / FOCUS_PIXAL) * 180 / PI; // double dy = -(circle_center_point.y - 240 - 22);
center_delta_pitch = atan(dy / FOCUS_PIXAL) * 180 / PI; //四号车
if (abs(center_delta_pitch) > 0.3 || abs(center_delta_pitch) > 0.3) { double dx = -(circle_center_point.x - 320 - 7);
sendTarget(serial, center_delta_yaw, center_delta_pitch, false); double dy = -(circle_center_point.y - 240 - 64);
center_delta_yaw = static_cast<float>(atan(dx / FOCUS_PIXAL) * 180 / PI);
center_delta_pitch = static_cast<float>(atan(dy / FOCUS_PIXAL) * 180 / PI);
if (abs(center_delta_yaw) > 0.3 || abs(center_delta_pitch) > 0.3) {
// cout << "origin not get!" << endl;
// cout << center_delta_yaw << '\t' << center_delta_pitch << endl;
sendTarget(serial, center_delta_yaw, center_delta_pitch, 0);
return false; return false;
} else { } else {
origin_yaw = mcuData.curr_yaw; origin_yaw = mcuData.curr_yaw;
origin_pitch = mcuData.curr_pitch; origin_pitch = mcuData.curr_pitch;
auto_mark = true; auto_mark = true;
sendTarget(serial, center_delta_yaw, center_delta_pitch, true); sendTarget(serial, center_delta_yaw, center_delta_pitch, 1);
LOGM(STR_CTR(WORD_BLUE_CODE, "auto mark success!")); LOGM(STR_CTR(WORD_BLUE_CODE, "auto mark success!"));
return true; return true;
} }

View File

@@ -27,6 +27,7 @@ bool Energy::isValidFanContour(cv::Mat &src, const vector<cv::Point> &fan_contou
if (length < energy_part_param_.FAN_CONTOUR_LENGTH_MIN || width < energy_part_param_.FAN_CONTOUR_WIDTH_MIN || 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) { length > energy_part_param_.FAN_CONTOUR_LENGTH_MAX || width > energy_part_param_.FAN_CONTOUR_WIDTH_MAX) {
//cout<<"length width fail."<<endl; //cout<<"length width fail."<<endl;
// cout << "length: " << length << '\t' << "width: " << width << '\t' << cur_rect.center << endl;
return false; return false;
//矩形边长不合适 //矩形边长不合适
} }
@@ -34,12 +35,14 @@ bool Energy::isValidFanContour(cv::Mat &src, const vector<cv::Point> &fan_contou
if (length_width_ratio > energy_part_param_.FAN_CONTOUR_HW_RATIO_MAX || if (length_width_ratio > energy_part_param_.FAN_CONTOUR_HW_RATIO_MAX ||
length_width_ratio < energy_part_param_.FAN_CONTOUR_HW_RATIO_MIN) { length_width_ratio < energy_part_param_.FAN_CONTOUR_HW_RATIO_MIN) {
//cout<<"length width ratio fail."<<endl; //cout<<"length width ratio fail."<<endl;
// cout << "HW: " << length_width_ratio << '\t' << cur_rect.center << endl;
return false; return false;
//长宽比不合适 //长宽比不合适
} }
// cout << cur_contour_area / cur_size.area() << endl; // cout << cur_contour_area / cur_size.area() << endl;
if (cur_contour_area / cur_size.area() < energy_part_param_.FAN_CONTOUR_AREA_RATIO_MIN) { if (cur_contour_area / cur_size.area() < energy_part_param_.FAN_CONTOUR_AREA_RATIO_MIN) {
// cout << cur_contour_area / cur_size.area() << endl; // cout << cur_contour_area / cur_size.area() << endl;
// cout << "area ratio: " << cur_contour_area / cur_size.area() << '\t' << cur_rect.center << endl;
return false;//轮廓对矩形的面积占有率不合适 return false;//轮廓对矩形的面积占有率不合适
} }
double non_zero_rate = nonZeroRateOfRotateRect(src, cur_rect); double non_zero_rate = nonZeroRateOfRotateRect(src, cur_rect);
@@ -71,6 +74,7 @@ bool Energy::isValidArmorContour(const vector<cv::Point> &armor_contour) {
if (length < energy_part_param_.ARMOR_CONTOUR_LENGTH_MIN || width < energy_part_param_.ARMOR_CONTOUR_WIDTH_MIN || 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) { length > energy_part_param_.ARMOR_CONTOUR_LENGTH_MAX || width > energy_part_param_.ARMOR_CONTOUR_WIDTH_MAX) {
//cout<<"length width fail."<<endl; //cout<<"length width fail."<<endl;
// cout << "length: " << length << '\t' << "width: " << width << '\t' << cur_rect.center << endl;
return false; return false;
//矩形边长不合适 //矩形边长不合适
} }
@@ -79,11 +83,14 @@ bool Energy::isValidArmorContour(const vector<cv::Point> &armor_contour) {
if (length_width_ratio > energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MAX || if (length_width_ratio > energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MAX ||
length_width_ratio < energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MIN) { length_width_ratio < energy_part_param_.ARMOR_CONTOUR_HW_RATIO_MIN) {
//cout<<"length width ratio fail."<<endl; //cout<<"length width ratio fail."<<endl;
// cout << "HW: " << length_width_ratio << '\t' << cur_rect.center << endl;
return false; return false;
//长宽比不合适 //长宽比不合适
} }
if (cur_contour_area / cur_size.area() < energy_part_param_.ARMOR_CONTOUR_AREA_RATIO_MIN) if (cur_contour_area / cur_size.area() < energy_part_param_.ARMOR_CONTOUR_AREA_RATIO_MIN) {
// cout << "area ratio: " << cur_contour_area / cur_size.area() << '\t' << cur_rect.center << endl;
return false;//轮廓对矩形的面积占有率不合适 return false;//轮廓对矩形的面积占有率不合适
}
return true; return true;
} }
@@ -108,6 +115,7 @@ bool Energy::isValidCenterRContour(const vector<cv::Point> &center_R_contour) {
|| length > energy_part_param_.CENTER_R_CONTOUR_LENGTH_MAX || || length > energy_part_param_.CENTER_R_CONTOUR_LENGTH_MAX ||
width > energy_part_param_.CENTER_R_CONTOUR_WIDTH_MAX) { width > energy_part_param_.CENTER_R_CONTOUR_WIDTH_MAX) {
//cout<<"length width fail."<<endl; //cout<<"length width fail."<<endl;
// cout << "length: " << length << '\t' << "width: " << width << '\t' << cur_rect.center << endl;
return false; return false;
//矩形边长不合适 //矩形边长不合适
} }
@@ -115,16 +123,19 @@ bool Energy::isValidCenterRContour(const vector<cv::Point> &center_R_contour) {
if (length_width_ratio > energy_part_param_.CENTER_R_CONTOUR_HW_RATIO_MAX || if (length_width_ratio > 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."<<endl; //cout<<"length width ratio fail."<<endl;
// cout << "HW: " << length_width_ratio << '\t' << cur_rect.center << endl;
return false; return false;
//长宽比不合适 //长宽比不合适
} }
if (cur_contour_area / cur_size.area() < energy_part_param_.CENTER_R_CONTOUR_AREA_RATIO_MIN) if (cur_contour_area / cur_size.area() < energy_part_param_.CENTER_R_CONTOUR_AREA_RATIO_MIN) {
// cout << "area ratio: " << cur_contour_area / cur_size.area() << '\t' << cur_rect.center << endl;
return false;//轮廓对矩形的面积占有率不合适 return false;//轮廓对矩形的面积占有率不合适
}
std::vector<cv::Point2f> intersection; std::vector<cv::Point2f> intersection;
if (rotatedRectangleIntersection(cur_rect, center_ROI, intersection) == 0) { if (rotatedRectangleIntersection(cur_rect, center_ROI, intersection) == 0) {
return false; return false;
} else if (contourArea(intersection) < energy_part_param_.CENTER_R_CONTOUR_INTERSETION_AREA_MIN) { } else if (contourArea(intersection) < energy_part_param_.CENTER_R_CONTOUR_INTERSETION_AREA_MIN) {
cout << "R intersection: " << contourArea(intersection) << endl; // cout << "R intersection: " << contourArea(intersection) << '\t' << cur_rect.center << endl;
return false; return false;
} }
return true; return true;
@@ -138,12 +149,12 @@ bool Energy::isValidFlowStripFanContour(cv::Mat &src, const vector<cv::Point> &f
double cur_contour_area = contourArea(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 || 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) { cur_contour_area < energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_MIN) {
// cout<<"area fail."<<endl; //cout<<"area fail."<<endl;
// cout << "area: " << cur_contour_area << '\t' << endl;
return false; return false;
//选区面积大小不合适 //选区面积大小不合适
} }
// cout<<cur_contour_area<<endl; // cout << "area: " << cur_contour_area << endl;
RotatedRect cur_rect = minAreaRect(flow_strip_fan_contour); RotatedRect cur_rect = minAreaRect(flow_strip_fan_contour);
Size2f cur_size = cur_rect.size; Size2f cur_size = cur_rect.size;
float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width;//将矩形的长边设置为长 float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width;//将矩形的长边设置为长
@@ -152,24 +163,23 @@ bool Energy::isValidFlowStripFanContour(cv::Mat &src, const vector<cv::Point> &f
|| width < energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MIN || width < energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MIN
|| length > energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MAX || length > energy_part_param_.FLOW_STRIP_FAN_CONTOUR_LENGTH_MAX
|| width > energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MAX) { || width > energy_part_param_.FLOW_STRIP_FAN_CONTOUR_WIDTH_MAX) {
// if(cur_contour_area>1600)
// cout<<"length: "<<length<<"width: "<<width<<endl;
// cout<<"length width fail."<<endl; // cout<<"length width fail."<<endl;
// cout << "length: " << length << '\t' << "width: " << width << '\t' << cur_rect.center << endl;
return false; return false;
//矩形边长不合适 //矩形边长不合适
} }
float length_width_ratio = length / width;//计算矩形长宽比 float length_width_ratio = length / width;//计算矩形长宽比
if (length_width_ratio > energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MAX || if (length_width_ratio > energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MAX ||
length_width_ratio < energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MIN) { length_width_ratio < energy_part_param_.FLOW_STRIP_FAN_CONTOUR_HW_RATIO_MIN) {
// cout<<"length width ratio fail."<<endl; //cout<<"length width ratio fail."<<endl;
// cout << "HW: " << length_width_ratio << '\t' << cur_rect.center << endl;
return false; return false;
//长宽比不合适 //长宽比不合适
} }
// cout << cur_contour_area / cur_size.area() << endl; // cout << cur_contour_area / cur_size.area() << endl;
if (cur_contour_area / cur_size.area() < energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MIN if (cur_contour_area / cur_size.area() < energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MIN
|| cur_contour_area / cur_size.area() > energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MAX) { || cur_contour_area / cur_size.area() > energy_part_param_.FLOW_STRIP_FAN_CONTOUR_AREA_RATIO_MAX) {
// if(cur_contour_area>1900) // cout << "area ratio: " << cur_contour_area / cur_size.area() << '\t' << cur_rect.center << endl;
// cout<<"size ratio: "<<cur_contour_area / cur_size.area()<<endl;
return false; return false;
} }
// 轮廓对矩形的面积占有率不合适 // 轮廓对矩形的面积占有率不合适
@@ -193,19 +203,11 @@ bool Energy::isValidFlowStripContour(const vector<cv::Point> &flow_strip_contour
if (cur_contour_area > energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MAX || if (cur_contour_area > energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MAX ||
cur_contour_area < energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MIN) { cur_contour_area < energy_part_param_.FLOW_STRIP_CONTOUR_AREA_MIN) {
// cout<<"area fail."<<endl; // cout<<"area fail."<<endl;
return false; return false;
//选区面积大小不合适 //选区面积大小不合适
} }
RotatedRect cur_rect = minAreaRect(flow_strip_contour); RotatedRect cur_rect = minAreaRect(flow_strip_contour);
std::vector<cv::Point2f> intersection;
if (rotatedRectangleIntersection(cur_rect, flow_strip_fan, intersection) == 0 ||
contourArea(intersection) < energy_part_param_.FLOW_STRIP_CONTOUR_INTERSETION_AREA_MIN) {
// cout<<"Intersection false!"<<endl;
return false;
//面积占比不合适
}
Size2f cur_size = cur_rect.size; Size2f cur_size = cur_rect.size;
float length = cur_size.height > cur_size.width ? cur_size.height : cur_size.width;//将矩形的长边设置为长 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;//将矩形的短边设置为宽 float width = cur_size.height < cur_size.width ? cur_size.height : cur_size.width;//将矩形的短边设置为宽
@@ -213,23 +215,30 @@ bool Energy::isValidFlowStripContour(const vector<cv::Point> &flow_strip_contour
width < energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MIN || width < energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MIN ||
length > energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MAX || length > energy_part_param_.FLOW_STRIP_CONTOUR_LENGTH_MAX ||
width > energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX) { width > energy_part_param_.FLOW_STRIP_CONTOUR_WIDTH_MAX) {
// if(cur_contour_area>600&&cur_contour_area<900)
// cout<<"length: "<<length<<" width: "<<width<<endl;
// cout<<"length width fail."<<endl; // cout<<"length width fail."<<endl;
// cout << "length: " << length << '\t' << "width: " << width << '\t' << cur_rect.center << endl;
return false; return false;
//矩形边长不合适 //矩形边长不合适
} }
// cout << length << '\t' << width << endl;
float length_width_ratio = length / width;//计算矩形长宽比 float length_width_ratio = length / width;//计算矩形长宽比
if (length_width_ratio > energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MAX || 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) { length_width_ratio < energy_part_param_.FLOW_STRIP_CONTOUR_HW_RATIO_MIN) {
// if(cur_contour_area>600&&cur_contour_area<900)
// cout<<"length: "<<length<<" width: "<<width<<" hw: "<<length_width_ratio<<endl;
// cout<<"hw fail."<<endl; // cout<<"hw fail."<<endl;
// cout << "HW: " << length_width_ratio << '\t' << cur_rect.center << endl;
return false; return false;
//长宽比不合适 //长宽比不合适
} }
if (cur_contour_area / cur_size.area() < energy_part_param_.FLOW_STRIP_CONTOUR_AREA_RATIO_MIN) 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;
return false;//轮廓对矩形的面积占有率不合适 return false;//轮廓对矩形的面积占有率不合适
}
std::vector<cv::Point2f> intersection;
if (rotatedRectangleIntersection(cur_rect, flow_strip_fan, intersection) == 0) {
return false;
} else if (contourArea(intersection) < energy_part_param_.FLOW_STRIP_CONTOUR_INTERSETION_AREA_MIN) {
// cout << "intersection: " << contourArea(intersection) << '\t' << cur_rect.center << endl;
return false;
}
return true; return true;
} }

View File

@@ -12,7 +12,7 @@ using namespace cv;
//---------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------
// 此函数用于判断大小符 // 此函数用于判断大小符
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
void Energy::JudgeMode() { void Energy::judgeMode() {
getRecentTargetArmorCenters(); getRecentTargetArmorCenters();
if (recent_target_armor_centers.size() < 30) { if (recent_target_armor_centers.size() < 30) {
return; return;

View File

@@ -4,23 +4,44 @@
#include "energy/energy.h" #include "energy/energy.h"
#include "log.h" #include "log.h"
#include "config/setconfig.h"
using namespace std; using namespace std;
using namespace cv; using namespace cv;
//---------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------
// 此函数用于判断是否可以发弹 // 此函数用于判断世界坐标系下是否可以发弹
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
void Energy::judgeShoot(){ void Energy::judgeShootInWorld(){
if (abs(yaw_rotation - mcuData.curr_yaw) < 0.3 && fabs(pitch_rotation - mcuData.curr_pitch) < 0.3) { if (abs(yaw_rotation - mcuData.curr_yaw) < 0.8 && fabs(pitch_rotation - mcuData.curr_pitch) < 0.8) {
shoot = true; shoot = 4;
is_predicting = false; is_predicting = false;
is_guessing = true; is_guessing = true;
start_guess = true; start_guess = true;
gettimeofday(&time_start_guess, NULL); gettimeofday(&time_start_guess, NULL);
LOGM(STR_CTR(WORD_LIGHT_RED, "Start Guessing!")); LOGM(STR_CTR(WORD_LIGHT_RED, "Start Guessing!"));
} else } else
shoot = false; shoot = 2;
}
//----------------------------------------------------------------------------------------------------------------------
// 此函数用于判断云台坐标系下是否可以发弹
// ---------------------------------------------------------------------------------------------------------------------
void Energy::judgeShootInGimbal(){
if (abs(yaw_rotation) < 0.5 && fabs(pitch_rotation) < 0.5) {
shoot = 4;
is_predicting = false;
is_guessing = true;
start_guess = true;
gettimeofday(&time_start_guess, NULL);
LOGM(STR_CTR(WORD_LIGHT_RED, "Start Guessing!"));
} else
shoot = 2;
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;
} }

View File

@@ -17,5 +17,5 @@ bool Energy::isGuessingTimeout() {
timeval cur_time; timeval cur_time;
gettimeofday(&cur_time, NULL); gettimeofday(&cur_time, NULL);
return (cur_time.tv_sec - time_start_guess.tv_sec) * 1000.0 + return (cur_time.tv_sec - time_start_guess.tv_sec) * 1000.0 +
(cur_time.tv_usec - time_start_guess.tv_usec) / 1000.0 > 500; (cur_time.tv_usec - time_start_guess.tv_usec) / 1000.0 > 1000;
}; };

View File

@@ -12,16 +12,15 @@ using namespace cv;
//---------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------
// 此函数为能量机关模式主控制流函数,且步兵需要同时拥有云台摄像头和底盘摄像头 // 此函数为能量机关模式主控制流函数,且步兵需要同时拥有云台摄像头和底盘摄像头
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
void Energy::run(cv::Mat &gimbal_src, cv::Mat &chassis_src) { void Energy::runBig(cv::Mat &gimbal_src, cv::Mat &chassis_src) {
if (chassis_src.empty()) if (chassis_src.empty())
run(gimbal_src);//仅拥有云台摄像头则调用单摄像头的run函数 runBig(gimbal_src);//仅拥有云台摄像头则调用单摄像头的run函数
else if (is_gimbal) { else if (is_gimbal) {
// energy_part_param_ = chassis_energy_part_param_;
energy_part_param_ = gimbal_energy_part_param_; energy_part_param_ = gimbal_energy_part_param_;
clearAll(); clearAll();
initImage(gimbal_src); initImage(gimbal_src);
findFans(gimbal_src); // findFans(gimbal_src);
showFans("fan",gimbal_src); // showFans("fan",gimbal_src);
if (findArmors(gimbal_src) < 1)return; if (findArmors(gimbal_src) < 1)return;
if (show_energy)showArmors("armor", gimbal_src); if (show_energy)showArmors("armor", gimbal_src);
@@ -32,12 +31,11 @@ void Energy::run(cv::Mat &gimbal_src, cv::Mat &chassis_src) {
if (!findCenterR(gimbal_src))return; if (!findCenterR(gimbal_src))return;
if (show_energy)showCenterR("R", gimbal_src); if (show_energy)showCenterR("R", gimbal_src);
if (!getOrigin())return; // if (!getOrigin())return;
startChassis(); startChassis();
initEnergy(); initEnergy();
destroyAllWindows(); destroyAllWindows();
} else if (is_chassis) { } else if (is_chassis) {
// energy_part_param_ = chassis_energy_part_param_;
energy_part_param_ = chassis_energy_part_param_; energy_part_param_ = chassis_energy_part_param_;
clearAll(); clearAll();
initImage(chassis_src); initImage(chassis_src);
@@ -47,35 +45,36 @@ void Energy::run(cv::Mat &gimbal_src, cv::Mat &chassis_src) {
if (findArmors(chassis_src) < 1)return; if (findArmors(chassis_src) < 1)return;
if (show_energy)showArmors("armor", chassis_src); if (show_energy)showArmors("armor", chassis_src);
if (!findFlowStripFan(chassis_src)) return; if (!findFlowStripFan(chassis_src))return;
if (!findTargetInFlowStripFan()) return; if (!findTargetInFlowStripFan()) return;
if (!findCenterROI(chassis_src))return; if (!findCenterROI(chassis_src))return;
if (show_energy)showFlowStripFan("strip", chassis_src); if (show_energy)showFlowStripFan("strip", chassis_src);
if (!findCenterR(chassis_src))return; if (!findCenterR(chassis_src))return;
if (show_energy)showCenterR("R", chassis_src); if (show_energy)showCenterR("R", chassis_src);
getTargetPolarAngle(); getTargetPolarAngle();
changeTarget(); changeTarget();
JudgeMode(); // judgeMode();
if (energy_mode_init)return; // if (energy_mode_init)return;
if (is_big && energy_rotation_init) { if (is_big && energy_rotation_init) {
initRotation(); initRotation();
return; return;
} }
if (is_predicting) { // if (is_predicting) {
getPredictPoint(target_point); // getPredictPoint(target_point);
gimbalRotation(); // gimbalRotation();
judgeShoot(); // judgeShootInWorld();
sendTarget(serial, yaw_rotation, pitch_rotation, shoot); // sendTarget(serial, yaw_rotation, pitch_rotation, shoot);
} else if (is_guessing && stayGuessing()) { // } else if (is_guessing && stayGuessing()) {
findFans(chassis_src); // findFans(chassis_src);
if (show_energy)showFans("fans", chassis_src); // if (show_energy)showFans("fans", chassis_src);
if (save_mark)writeDownMark(); // if (save_mark)writeDownMark();
if (!guessTarget()) return; // if (!guessTarget()) return;
if (show_energy)showGuessTarget("guess", chassis_src); // if (show_energy)showGuessTarget("guess", chassis_src);
getPredictPoint(guess_point); // getPredictPoint(guess_point);
gimbalRotation(); // gimbalRotation();
sendTarget(serial, yaw_rotation, pitch_rotation, false); // sendTarget(serial, yaw_rotation, pitch_rotation, 5);
} // }
} }
} }
@@ -83,7 +82,7 @@ void Energy::run(cv::Mat &gimbal_src, cv::Mat &chassis_src) {
//---------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------
// 此函数为能量机关模式主控制流函数,且步兵仅拥有云台摄像头 // 此函数为能量机关模式主控制流函数,且步兵仅拥有云台摄像头
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
void Energy::run(cv::Mat &gimbal_src) { void Energy::runBig(cv::Mat &gimbal_src) {
energy_part_param_ = gimbal_energy_part_param_; energy_part_param_ = gimbal_energy_part_param_;
clearAll(); clearAll();
initImage(gimbal_src); initImage(gimbal_src);
@@ -102,17 +101,24 @@ void Energy::run(cv::Mat &gimbal_src) {
if (show_energy)showCenterR("R", gimbal_src); if (show_energy)showCenterR("R", gimbal_src);
changeTarget(); changeTarget();
getTargetPolarAngle(); getTargetPolarAngle();
JudgeMode(); // cout<<circle_center_point<<endl;
if (energy_mode_init)return; // cout << target_point << '\t' << target_polar_angle << endl;
if (!getOrigin())return; // cout << circle_center_point<< endl;
if (is_big && energy_rotation_init) {
// judgeMode();
// if (energy_mode_init)return;
// if (!getOrigin())return;
if (energy_rotation_init) {
initRotation(); initRotation();
return; return;
} }
if (is_predicting) { if (is_predicting) {
getPredictPoint(target_point); getPredictPoint(target_point);
gimbalRotation(); getAimPoint(predict_point);
judgeShoot(); // cout << yaw_rotation << '\t' << pitch_rotation << endl;
judgeShootInGimbal();
sendTarget(serial, yaw_rotation, pitch_rotation, shoot); sendTarget(serial, yaw_rotation, pitch_rotation, shoot);
} else if (is_guessing && stayGuessing()) { } else if (is_guessing && stayGuessing()) {
findFans(gimbal_src); findFans(gimbal_src);
@@ -121,7 +127,67 @@ void Energy::run(cv::Mat &gimbal_src) {
guessTarget(); guessTarget();
if (show_energy)showGuessTarget("guess", gimbal_src); if (show_energy)showGuessTarget("guess", gimbal_src);
getPredictPoint(guess_point); getPredictPoint(guess_point);
gimbalRotation(); getAimPoint(predict_point);
sendTarget(serial, yaw_rotation, pitch_rotation, false); sendTarget(serial, yaw_rotation, pitch_rotation, 5);
} }
} }
//----------------------------------------------------------------------------------------------------------------------
// 此函数为小能量机关模式主控制流函数,击打小符只需要拥有云台摄像头
// ---------------------------------------------------------------------------------------------------------------------
void Energy::runSmall(cv::Mat &gimbal_src) {
energy_part_param_ = gimbal_energy_part_param_;
clearAll();
initImage(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 (!findCenterROI(gimbal_src))return;
// if (show_energy)showFlowStripFan("strip", gimbal_src);
// if (!findCenterR(gimbal_src))return;
// if (show_energy)showCenterR("R", gimbal_src);
changeTarget();
// cout << "target point: " << target_point << endl;
if (is_predicting) {
getAimPoint(target_point);
judgeShootInGimbal();
sendTarget(serial, yaw_rotation, pitch_rotation, shoot);
} else if (is_guessing && stayGuessing()) {
findFans(gimbal_src);
if (show_energy)showFans("fans", gimbal_src);
if (save_mark)writeDownMark();
guessTarget();
if (show_energy)showGuessTarget("guess", gimbal_src);
getAimPoint(guess_point);
sendTarget(serial, yaw_rotation, pitch_rotation, 5);
}
}
//getPredictPoint(target_point);
//gimbalRotation();
//static bool k = false;
//cout<<"delta yaw: "<<abs(yaw_rotation - mcuData.curr_yaw)<<endl;
//cout<<"delta pitch: "<<abs(pitch_rotation - mcuData.curr_pitch)<<endl;
//cout << "origin_yaw: " << origin_yaw << '\t' << "origin_pitch: " << origin_pitch << endl;
//cout << "predict point: " << predict_point << endl;
//
//if (abs(yaw_rotation - mcuData.curr_yaw) < 0.8 && abs(pitch_rotation - mcuData.curr_pitch) < 0.6) {
//shoot = 4;
//if (!k) {
//sendTarget(serial, yaw_rotation, pitch_rotation, shoot);
//cout << "yaw: " << yaw_rotation << '\t' << "pitch: " << pitch_rotation << endl;
//k = false;
//}
//waitKey(400);
//} else {
//shoot = 2;
//sendTarget(serial, yaw_rotation, pitch_rotation, shoot);
//}

View File

@@ -43,7 +43,6 @@ void Energy::stretch(cv::Point point_1, cv::Point2f &point_2) {
double x_0 = point_1.x - circle_center_point.x; double x_0 = point_1.x - circle_center_point.x;
double y_0 = point_1.y - circle_center_point.y; double y_0 = point_1.y - circle_center_point.y;
double r_0 = sqrt(pow(x_0, 2) + pow(y_0, 2)); double r_0 = sqrt(pow(x_0, 2) + pow(y_0, 2));
point_2.x = static_cast<float >( ARMOR_CENTER_TO_CYCLE_CENTER * x_0 / r_0); point_2.x = static_cast<float >( ARMOR_CENTER_TO_CYCLE_CENTER * x_0 / r_0);
point_2.y = static_cast<float >( ARMOR_CENTER_TO_CYCLE_CENTER * y_0 / r_0); point_2.y = static_cast<float >( ARMOR_CENTER_TO_CYCLE_CENTER * y_0 / r_0);
} }

View File

@@ -30,7 +30,7 @@ using namespace std;
mcu_data mcuData = { // 单片机端回传结构体 mcu_data mcuData = { // 单片机端回传结构体
0, // 当前云台yaw角 0, // 当前云台yaw角
0, // 当前云台pitch角 0, // 当前云台pitch角
BIG_ENERGY_STATE, // 当前状态,自瞄-大符-小符 ARMOR_STATE, // 当前状态,自瞄-大符-小符
0, // 云台角度标记位 0, // 云台角度标记位
1, // 是否启用数字识别 1, // 是否启用数字识别
ENEMY_RED, // 敌方颜色 ENEMY_RED, // 敌方颜色
@@ -64,10 +64,8 @@ int main(int argc, char *argv[]) {
video_gimbal = new CameraWrapper(0/*, "armor"*/); video_gimbal = new CameraWrapper(0/*, "armor"*/);
video_chassis = new CameraWrapper(1/*, "energy"*/); video_chassis = new CameraWrapper(1/*, "energy"*/);
} else { } else {
video_gimbal = new VideoWrapper("/home/sjturm/Desktop/videos/gimbal84.avi"); video_gimbal = new VideoWrapper("/home/sun/项目/energy_video/gimbal132.avi");
video_chassis = new VideoWrapper("/home/sjturm/Desktop/videos/gimbal84.avi"); video_chassis = new VideoWrapper("/home/sun/项目/energy_video/gimbal132.avi");
// video_gimbal = new VideoWrapper("/home/sjturm/Desktop/dafu/gimble3.avi");
// video_chassis = new VideoWrapper("/home/sjturm/Desktop/dafu/chassis3.avi");
} }
if (video_gimbal->init()) { if (video_gimbal->init()) {
LOGM("video_gimbal source initialization successfully."); LOGM("video_gimbal source initialization successfully.");
@@ -93,19 +91,18 @@ int main(int argc, char *argv[]) {
bool ok = true; bool ok = true;
cout << "start running" << endl; cout << "start running" << endl;
do { do {
CNT_TIME("Total", { // CNT_TIME("Total", {
if (mcuData.state != ARMOR_STATE) {//能量机关模式 if (mcuData.state == BIG_ENERGY_STATE) {//能量机关模式
if (last_state == ARMOR_STATE) {//若上一帧是自瞄模式,即刚往完成切换,则需要初始化 if (last_state != BIG_ENERGY_STATE) {//若上一帧不是大能量机关模式,即刚往完成切换,则需要初始化
destroyAllWindows(); destroyAllWindows();
((CameraWrapper *) video_gimbal)->changeBrightness(ENERGY_CAMERA_GAIN); ((CameraWrapper *) video_gimbal)->changeBrightness(ENERGY_CAMERA_GAIN);
energy.setEnergyInit(); energy.setBigEnergyInit();
checkReconnect(video_chassis->read(chassis_src)); checkReconnect(video_chassis->read(chassis_src));
#ifdef CHASSIS_FLIP_MODE #ifdef CHASSIS_FLIP_MODE
flip(chassis_src, chassis_src, CHASSIS_FLIP_MODE); flip(chassis_src, chassis_src, CHASSIS_FLIP_MODE);
#endif #endif
} }
ok = checkReconnect(video_gimbal->read(gimbal_src)); ok = checkReconnect(video_gimbal->read(gimbal_src));
video_gimbal->read(gimbal_src);
video_chassis->read(chassis_src); video_chassis->read(chassis_src);
#ifdef GIMBAL_FLIP_MODE #ifdef GIMBAL_FLIP_MODE
flip(gimbal_src, gimbal_src, GIMBAL_FLIP_MODE); flip(gimbal_src, gimbal_src, GIMBAL_FLIP_MODE);
@@ -113,8 +110,23 @@ int main(int argc, char *argv[]) {
if (!from_camera) extract(gimbal_src, chassis_src); if (!from_camera) extract(gimbal_src, chassis_src);
if (save_video) saveVideos(gimbal_src, chassis_src);//保存视频 if (save_video) saveVideos(gimbal_src, chassis_src);//保存视频
if (show_origin) showOrigin(gimbal_src, chassis_src);//显示原始图像 if (show_origin) showOrigin(gimbal_src, chassis_src);//显示原始图像
// energy.run(gimbal_src, chassis_src); // energy.runBig(gimbal_src, chassis_src);
energy.run(gimbal_src); energy.runBig(gimbal_src);
last_state = mcuData.state;//更新上一帧状态
} else if (mcuData.state == SMALL_ENERGY_STATE) {
if (mcuData.state != SMALL_ENERGY_STATE) {
destroyAllWindows();
((CameraWrapper *) video_gimbal)->changeBrightness(ENERGY_CAMERA_GAIN);
energy.setSmallEnergyInit();
}
ok = checkReconnect(video_gimbal->read(gimbal_src));
#ifdef GIMBAL_FLIP_MODE
flip(gimbal_src, gimbal_src, GIMBAL_FLIP_MODE);
#endif
if (!from_camera) extract(gimbal_src);
if (save_video) saveVideos(gimbal_src);//保存视频
if (show_origin) showOrigin(gimbal_src);//显示原始图像
energy.runSmall(gimbal_src);
last_state = mcuData.state;//更新上一帧状态 last_state = mcuData.state;//更新上一帧状态
} else { // 自瞄模式 } else { // 自瞄模式
if (last_state != ARMOR_STATE) { if (last_state != ARMOR_STATE) {
@@ -133,8 +145,8 @@ int main(int argc, char *argv[]) {
armorFinder.run(gimbal_src); armorFinder.run(gimbal_src);
}); });
} }
cv::waitKey(1); // cv::waitKey(0);
}); // });
} while (ok); } while (ok);
delete video_gimbal; delete video_gimbal;
video_gimbal = nullptr; video_gimbal = nullptr;

View File

@@ -48,6 +48,7 @@ public:
bool readRaw(cv::Mat& src); bool readRaw(cv::Mat& src);
bool readProcessed(cv::Mat& src); bool readProcessed(cv::Mat& src);
bool changeBrightness(int brightness); bool changeBrightness(int brightness);
// bool once
}; };

View File

@@ -30,6 +30,18 @@
#ifndef ENERGY_CAMERA_GAIN #ifndef ENERGY_CAMERA_GAIN
#define ENERGY_CAMERA_GAIN (20) #define ENERGY_CAMERA_GAIN (20)
#endif #endif
#ifndef AIM_KP
#define AIM_KP (6)
#endif
#ifndef AIM_KI
#define AIM_KI (0.1)
#endif
#ifndef COMPENSATE_YAW
#define COMPENSATE_YAW (5)
#endif
#ifndef COMPENSATE_PITCH
#define COMPENSATE_PITCH (74)
#endif
//#define GIMBAL_FLIP_MODE (-1) //#define GIMBAL_FLIP_MODE (-1)
//#define CHASSIS_FLIP_MODE (-1) //#define CHASSIS_FLIP_MODE (-1)

View File

@@ -30,27 +30,27 @@ extern ArmorFinder armorFinder;
extern Energy energy; extern Energy energy;
void uartReceive(Serial *pSerial) { void uartReceive(Serial *pSerial) {
char buffer[20]; char buffer[30];
int cnt = 0;
LOGM(STR_CTR(WORD_LIGHT_WHITE, "data receive start!")); LOGM(STR_CTR(WORD_LIGHT_WHITE, "data receive start!"));
while (true) { while (true) {
char byte = 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
while (pSerial->ReadData((uint8_t *) &byte, 1) && byte != '\n') { pSerial->ReadData((uint8_t *) buffer, sizeof(mcuData)+1);
buffer[cnt++] = byte; if (buffer[sizeof(mcuData)] == '\n') {
if (cnt >= sizeof(buffer)) {
// LOGE("data receive over flow!");
cnt = 0;
}
}
if (cnt == 0 && byte == '\n') {
// LOGM("%d", cnt);
}
if (cnt == sizeof(mcuData)) {
memcpy(&mcuData, buffer, sizeof(mcuData)); memcpy(&mcuData, buffer, sizeof(mcuData));
// LOGM("Get, state:%c, mark:%d!", mcuData.state, (int) mcuData.mark); // LOGM("Get, state:%c, mark:%d!", mcuData.state, (int) mcuData.mark);
// LOGM("Get yaw: %f, pitch: %f!", mcuData.curr_yaw, mcuData.curr_pitch);
// static int t = time(nullptr);
// static int cnt = 0;
// if(time(nullptr) > t){
// t = time(nullptr);
// LOGM("fps:%d", cnt);
// cnt = 0;
// }else{
// cnt++;
// }
}else{
// LOGW("corrupt data!");
} }
cnt = 0;
} }
} }
@@ -76,12 +76,12 @@ cv::VideoWriter initVideoWriter(const std::string &filename_prefix) {
bool checkReconnect(bool is_camera_0_connect, bool is_camera_1_connect) { bool checkReconnect(bool is_camera_0_connect, bool is_camera_1_connect) {
if (!is_camera_0_connect) { if (!is_camera_0_connect) {
delete video_gimbal; delete video_gimbal;
video_gimbal = new CameraWrapper(0, "armor"); video_gimbal = new CameraWrapper(0/*, "armor"*/);
is_camera_0_connect = video_gimbal->init(); is_camera_0_connect = video_gimbal->init();
} }
if (!is_camera_1_connect) { if (!is_camera_1_connect) {
delete video_chassis; delete video_chassis;
video_chassis = new CameraWrapper(1, "energy"); video_chassis = new CameraWrapper(1/*, "energy"*/);
is_camera_1_connect = video_chassis->init(); is_camera_1_connect = video_chassis->init();
} }
return is_camera_0_connect && is_camera_1_connect; return is_camera_0_connect && is_camera_1_connect;
@@ -90,7 +90,7 @@ bool checkReconnect(bool is_camera_0_connect, bool is_camera_1_connect) {
bool checkReconnect(bool is_camera_connect) { bool checkReconnect(bool is_camera_connect) {
if (!is_camera_connect) { if (!is_camera_connect) {
delete video_gimbal; delete video_gimbal;
video_gimbal = new CameraWrapper(0, "armor"); video_gimbal = new CameraWrapper(0/*, "armor"*/);
is_camera_connect = video_gimbal->init(); is_camera_connect = video_gimbal->init();
} }
return is_camera_connect; return is_camera_connect;

View File

@@ -191,7 +191,7 @@ Serial::Serial(int nSpeed, char nEvent, int nBits, int nStop) :
nSpeed(nSpeed), nEvent(nEvent), nBits(nBits), nStop(nStop) { nSpeed(nSpeed), nEvent(nEvent), nBits(nBits), nStop(nStop) {
if (wait_uart) { if (wait_uart) {
LOGM("Wait for serial be ready!"); LOGM("Wait for serial be ready!");
while (InitPort(nSpeed, nEvent, nBits, nStop) == false); while (!InitPort(nSpeed, nEvent, nBits, nStop));
LOGM("Port set successfully!"); LOGM("Port set successfully!");
} else { } else {
if (InitPort(nSpeed, nEvent, nBits, nStop)) { if (InitPort(nSpeed, nEvent, nBits, nStop)) {
@@ -234,7 +234,7 @@ bool Serial::WriteData(const unsigned char *pData, unsigned int length) {
return false; return false;
} }
while ((curr = write(fd, pData + cnt, length - cnt)) > 0 && (cnt += curr) < length); while ((curr = write(fd, pData + cnt, length - cnt)) > 0 && (cnt += curr) < length);
if (cnt < 0) { if (curr < 0) {
LOGE("Serial offline!"); LOGE("Serial offline!");
close(fd); close(fd);
if (wait_uart) { if (wait_uart) {
@@ -248,7 +248,7 @@ bool Serial::WriteData(const unsigned char *pData, unsigned int length) {
bool Serial::ReadData(unsigned char *buffer, unsigned int length) { bool Serial::ReadData(unsigned char *buffer, unsigned int length) {
int cnt = 0, curr = 0; int cnt = 0, curr = 0;
while ((curr = read(fd, buffer + cnt, length - cnt)) > 0 && (cnt += curr) < length); while ((curr = read(fd, buffer + cnt, length - cnt)) > 0 && (cnt += curr) < length);
if (cnt < 0) { if (curr < 0) {
LOGE("Serial offline!"); LOGE("Serial offline!");
close(fd); close(fd);
if (wait_uart) { if (wait_uart) {

View File

@@ -54,16 +54,14 @@ def save_para(folder, paras):
save_bias(fp, paras[7]) save_bias(fp, paras[7])
STEPS = 10000 STEPS = 100000
BATCH = 30 BATCH = 50
LEARNING_RATE_BASE = 0.005 LEARNING_RATE_BASE = 0.001
LEARNING_RATE_DECAY = 0.99 LEARNING_RATE_DECAY = 0.99
MOVING_AVERAGE_DECAY = 0.99 MOVING_AVERAGE_DECAY = 0.99
def train(dataset, show_bar=False): def train(dataset, show_bar=False):
test_images, test_labels = dataset.all_test_sets()
x = tf.placeholder(tf.float32, [None, generate.SRC_ROWS, generate.SRC_COLS, generate.SRC_CHANNELS]) x = tf.placeholder(tf.float32, [None, generate.SRC_ROWS, generate.SRC_COLS, generate.SRC_CHANNELS])
y_= tf.placeholder(tf.float32, [None, forward.OUTPUT_NODES]) y_= tf.placeholder(tf.float32, [None, forward.OUTPUT_NODES])
keep_rate = tf.placeholder(tf.float32) keep_rate = tf.placeholder(tf.float32)
@@ -103,11 +101,12 @@ def train(dataset, show_bar=False):
_, loss_value, step = sess.run( _, loss_value, step = sess.run(
[train_op, loss, global_step], [train_op, loss, global_step],
feed_dict={x: images_samples, y_: labels_samples, keep_rate:0.5} feed_dict={x: images_samples, y_: labels_samples, keep_rate:0.3}
) )
if i % 100 == 0: if i % 100 == 0:
if i % 1000 == 0: if i % 500 == 0:
test_images, test_labels = dataset.sample_test_sets(10000)
acc = sess.run(accuracy, feed_dict={x: test_images, y_: test_labels, keep_rate:1.0}) acc = sess.run(accuracy, feed_dict={x: test_images, y_: test_labels, keep_rate:1.0})
bar.set_postfix({"loss": loss_value, "acc": acc}) bar.set_postfix({"loss": loss_value, "acc": acc})
@@ -116,6 +115,9 @@ def train(dataset, show_bar=False):
vars_val = sess.run(vars) vars_val = sess.run(vars)
save_para("/home/xinyang/Workspace/RM_auto-aim/tools/para", vars_val) save_para("/home/xinyang/Workspace/RM_auto-aim/tools/para", vars_val)
print("save done!") print("save done!")
# pred = sess.run(y, feed_dict={x: test_images, keep_rate:1.0})
# nodes_val = sess.run(nodes, feed_dict={x:test_images}) # nodes_val = sess.run(nodes, feed_dict={x:test_images})
# return vars_val, nodes_val # return vars_val, nodes_val
DevList = mvsdk.CameraEnumerateDevice() DevList = mvsdk.CameraEnumerateDevice()

View File

@@ -35,10 +35,10 @@ CONV1_OUTPUT_CHANNELS = 6
CONV2_KERNAL_SIZE = 3 CONV2_KERNAL_SIZE = 3
# 第二层卷积输出通道数 # 第二层卷积输出通道数
CONV2_OUTPUT_CHANNELS = 10 CONV2_OUTPUT_CHANNELS = 12
# 第一层全连接宽度 # 第一层全连接宽度
FC1_OUTPUT_NODES = 16 FC1_OUTPUT_NODES = 30
# 第二层全连接宽度(输出标签类型数) # 第二层全连接宽度(输出标签类型数)
FC2_OUTPUT_NODES = 15 FC2_OUTPUT_NODES = 15

View File

@@ -40,7 +40,7 @@ class DataSet:
files = os.listdir(dir) files = os.listdir(dir)
for file in tqdm(files, postfix={"loading id": i}, dynamic_ncols=True): for file in tqdm(files, postfix={"loading id": i}, dynamic_ncols=True):
if file[-3:] == "jpg": if file[-3:] == "jpg":
if random.random() > 0.2: if random.random() > 0.7:
self.train_samples.append(self.file2nparray("%s/%s" % (dir, file))) self.train_samples.append(self.file2nparray("%s/%s" % (dir, file)))
self.train_labels.append(self.id2label(i)) self.train_labels.append(self.id2label(i))
else: else:
@@ -61,6 +61,15 @@ class DataSet:
labels.append(self.train_labels[id]) labels.append(self.train_labels[id])
return np.array(samples), np.array(labels) return np.array(samples), np.array(labels)
def sample_test_sets(self, length):
samples = []
labels = []
for i in range(length):
id = random.randint(0, len(self.test_samples)-1)
samples.append(self.test_samples[id])
labels.append(self.test_labels[id])
return np.array(samples), np.array(labels)
def all_train_sets(self): def all_train_sets(self):
return self.train_samples[:], self.train_labels[:] return self.train_samples[:], self.train_labels[:]

View File

@@ -2,5 +2,5 @@
echo "#!/bin/bash" > $2/startup-run echo "#!/bin/bash" > $2/startup-run
echo "$1/tools/auto-pull.sh" >> $2/startup-run echo "$1/tools/auto-pull.sh" >> $2/startup-run
echo "gnome-terminal -- bash -c \"echo sjturm | sudo -S $1/tools/monitor.sh \\\"$2/run --run-with-camera --save-video --wait-uart --save-labelled-boxes --show-armor-box\\\"\"" >> $2/startup-run echo "gnome-terminal -- bash -c \"echo sjturm | sudo -S $1/tools/monitor.sh \\\"$2/run --run-with-camera --save-video --wait-uart --save-labelled-boxes\\\"\"" >> $2/startup-run
chmod +x $2/startup-run chmod +x $2/startup-run

View File

@@ -1,7 +1,7 @@
6 6
-0.012731806 -0.20627302
-0.68924344 1.6024942
1.0428871 1.7967451
0.09240551 1.4466392
0.87806237 -0.098023266
-0.51778877 -0.006771178

View File

@@ -2,453 +2,453 @@
6 6
5 5
5 5
-0.0705555 -0.10642219
0.086937346 0.54904705
0.297247 1.0220182
0.51908225 1.2654289
0.41566578 1.0080621
0.22415005 0.63893425
0.21470949 1.0596974
0.42054617 1.5017769
0.57512695 1.7486153
0.50255156 1.2255592
0.2663179 0.7572802
0.10764991 1.1565144
0.32504323 1.2662624
0.27210033 1.3252954
0.32694185 1.1559033
0.18968254 0.22455153
-0.03312495 0.46842065
-0.28554282 0.6101949
-0.27717206 0.6682584
0.010500877 0.1469474
-0.16386741 -0.19053003
-0.58856106 -0.30085373
-1.0167654 -0.505979
-0.59654444 -0.6151139
-0.07342564 -0.7488737
0.6650266 -0.67636555
0.6682501 -0.7467412
0.61575854 -0.7404055
0.20123789 -0.77479744
0.13246079 -0.75153095
0.9794644 -0.5121083
0.9181109 -0.580226
0.75080305 -0.57781655
0.5678118 -0.6191948
0.17880438 -0.4956569
0.8291312 -0.5530203
0.9157011 -0.54242903
0.8058578 -0.58190167
0.6174977 -0.808631
0.3349475 -0.5255669
0.93871576 -0.5567334
1.0840453 -0.65943664
0.9012157 -0.675188
0.6562343 -0.7753057
0.28151926 -0.5219072
0.8399793 -0.4224288
0.9920022 -0.4372446
0.64904636 -0.65674895
0.6055482 -0.88619053
0.15666491 -0.5918416
-0.8087083 0.45536855
-0.5565874 0.382092
-0.8960519 -0.017086059
-0.80074924 -0.4412066
-0.74640626 -0.32249
-0.2773623 0.5902474
-0.20795147 0.4910132
-0.1870408 0.02227385
-0.15045224 -0.4520488
-0.13983378 -0.6278883
-0.10816965 0.60164636
0.031628396 0.3453617
-0.116946414 0.16053873
-0.013991349 -0.39892384
0.21591163 -0.4782997
-0.18964738 0.56412727
0.0040286863 0.5470579
-0.30242768 0.33888572
-0.24229145 -0.025963284
0.23588136 0.010916833
-0.331128 0.7818745
-0.5470479 0.9463605
-0.7203085 0.72511697
-0.6601643 0.44537586
-0.05225026 0.35324848
0.45265025 -0.6419165
0.75259274 -0.347417
0.74857485 -0.40558645
0.7100708 -0.50654674
0.34476462 -0.44879192
0.46986035 -0.49447027
0.5765347 -0.31920582
0.6258838 -0.1661499
0.3804861 -0.4432326
0.3160558 -0.33963177
0.6183596 -0.38981852
0.59951615 -0.4906231
0.60037804 -0.45195618
0.6340707 -0.52474713
0.34009996 -0.39969632
0.7194144 -0.4819537
0.8571618 -0.71747667
0.94336456 -0.821255
0.90685135 -0.8445041
0.41317853 -0.89447993
1.0044444 -0.859059
1.0062212 -0.98320967
1.0895951 -1.0902424
0.92497915 -1.105878
0.7468299 -1.2187494
-1.2501324 0.67084956
-0.74794984 0.9035801
-0.047555014 1.2065095
0.49243745 1.3081064
0.8178278 1.2326727
-1.2034731 1.0170805
-0.49681732 1.0677104
0.015281494 1.5938762
0.60018766 1.4207084
0.713024 1.3485196
-0.84448695 1.0809016
-0.0899703 1.3998586
0.09781959 1.7368488
0.4817282 1.5395899
0.51024574 1.5694551
0.010328657 1.3630624
0.2768326 1.4492949
0.6458937 1.5428637
0.65859175 1.393225
0.39070535 1.4149159
0.60249025 1.1494107
1.1937758 1.2268404
0.9160051 1.2541622
0.8284883 0.96135026
0.53566974 0.90241027
-0.4362068 -0.31921467
-0.2836022 -0.110522695
-0.32180697 0.09325943
0.022249598 -0.0139649
0.29908466 -0.028535917
-0.5530434 -0.24136181
-0.4986115 0.03892438
-0.278484 0.20345062
-0.31018886 -0.074525945
-0.24363342 -0.029405555
-0.35979065 -0.07647651
-0.43008342 -0.15445644
-0.37437305 -0.058089375
-0.30203703 -0.40588626
-0.5734246 -0.27692583
0.02336341 -0.2698881
-0.25258422 -0.55068505
-0.3121478 -0.5919062
-0.6288646 -0.5438777
-0.4711073 -0.5993602
0.12114608 -0.7458306
-0.061813425 -0.81796175
-0.12937883 -0.94331497
-0.6477893 -1.0076928
-0.6810196 -0.8992378
1.8673725 1.9416478
2.8808968 3.2734282
3.1819828 4.160874
3.0621288 4.7219324
2.5003161 4.1175704
2.4616675 3.0404797
3.2074707 4.511751
3.5739362 5.663269
3.1081522 5.930972
2.4229178 4.7846756
2.4271266 3.3442042
3.280304 4.758655
3.0261867 5.6102233
2.3990371 5.5837803
1.8921077 4.3014107
2.005818 2.793397
2.4233122 3.7502306
2.1124473 4.3392096
1.5049059 4.142601
1.0315852 2.9172728
1.0267158 1.819791
0.8723091 2.428208
0.44316038 2.3962913
0.1576413 2.0173726
0.22018914 1.0743914
0.18436278 0.26512346
-0.04525133 0.3457875
-0.28330094 0.58334744
-0.50770444 0.40681112
-0.4281736 0.40550798
0.26419267 0.29478824
0.16408478 0.732128
0.19734842 0.8325436
-0.2016362 0.603493
-0.32106283 0.7258464
0.64052576 0.5068629
0.45036018 0.67576087
0.42224813 0.74854803
0.106944986 0.60851085
-0.15083833 0.77726454
0.9302013 0.3519754
0.7691678 0.468439
0.6336322 0.6548478
0.078011096 0.70905083
-0.031026825 0.3086395
0.80035543 0.4289891
0.60188663 0.47042668
0.38603687 0.37940606
-0.03504348 0.45548278
-0.19659142 0.14207979
0.61344516 0.71661115
0.8947993 0.09474261
0.97315925 -0.7471369
0.74691004 -1.7338398
0.49092364 -2.5905223
1.2537221 0.7082176
1.9796665 0.21243899
1.9934042 -0.6654869
1.6571536 -1.7607315
1.5510287 -2.7247927
1.7490395 0.6009304
2.4188108 0.10814533
2.487965 -0.6752587
2.0581145 -1.7909975
1.922978 -2.3464935
1.7984617 0.79290503
2.3430247 0.49252048
2.2450094 -0.43408415
1.9467311 -1.3109739
1.6972682 -1.9383324
1.2808937 0.9131795
1.5145483 0.58063436
1.4981558 -0.065964356
1.1744506 -0.84630096
1.2942766 -1.3107594
-0.028776312 0.9702296
0.08628688 1.7605543
0.14530973 1.9099594
0.060263254 1.8536079
-0.1992724 1.3434014
-0.3509845 1.1538997
-0.14943084 1.8189181
0.05269242 1.9872671
-0.047488246 2.0980296
-0.32251114 1.5539708
-0.055337034 0.9389947
-0.0606678 1.4959635
0.13780722 1.8016711
0.025866544 1.5903975
-0.2515092 1.2731018
0.36665168 0.78981453
0.4256815 1.0439569
0.44711438 1.3309318
0.45632693 1.2204188
0.18695426 0.78188473
0.83469534 0.41300166
0.73099476 0.4995686
0.90957487 0.52244127
0.7863896 0.5596004
0.60097635 0.21890602
-2.77742 0.30612093
-1.898205 0.85429645
-0.51413226 1.2398238
0.29049698 1.2750283
0.93399036 1.3086212
-2.6324046 1.0696554
-1.413464 1.3433759
-0.11643134 1.729579
0.7600749 1.7326889
1.0856903 1.7986484
-2.0343983 1.3991985
-0.7860615 1.7318608
0.3931903 2.0507987
1.0088302 1.941499
1.2542579 1.7631179
-1.0282527 1.4714234
0.00558986 1.8296314
0.7271341 1.9416764
1.2017635 1.8468171
0.9958149 1.6414593
0.2970806 1.4085735
1.2236876 1.5106102
1.36118 1.610607
1.3418391 1.5357318
0.8660408 1.1668565
-1.1435972 1.3847203
-0.83455884 1.9328053
-0.7378884 2.0932007
-0.20356347 1.6669843
0.21133415 1.3775337
-0.84094524 1.6736194
-1.1279244 2.307166
-0.6961366 2.3085163
-0.4854085 2.008549
-0.026166996 1.2341207
-0.54931265 1.6037624
-0.4710362 2.0786712
-0.7298363 1.9735341
-0.64001644 1.5647856
-0.62205493 1.02917
0.03693532 1.3709607
-0.40307578 1.4461753
-0.4964193 1.256765
-0.42969394 0.9555051
-0.5397872 0.36569837
0.3220369 0.7852095
0.14219745 0.7917901
-0.4169855 0.43664944
-0.48323318 0.2549527
-0.77415246 -0.067954175
-0.4052389 0.20057896
0.5951485 1.3856035
0.4901534 2.0629358
0.51781464 2.809679
0.026524775 2.3610249
0.19928466 0.83472407
0.8500332 2.064841
0.8974233 3.0214195
0.75791407 3.401786
0.29939106 2.7669187
0.1305985 1.1871954
0.94468176 2.2021434
0.8779284 2.9477324
0.47177282 3.2896252
0.018099217 2.3611999
-0.2669419 0.58470565
0.14852984 1.433704
0.17997491 1.8206064
-0.40414903 1.6048844
-0.57394934 1.0893
-0.8052322 0.079494156
-0.6834026 0.14756773
-0.9813351 0.21510047
-1.2330854 0.17841841
-1.1226501 -0.3402442
-0.2375166 0.82796144
-0.25760472 0.89763546
-0.6702083 0.9589713
-0.83058023 0.86110723
-0.845694 0.6416584
-0.035079293 1.0780864
0.15334488 1.2395475
-0.20645554 1.4097389
-0.6201716 1.1237956
-0.58026224 1.0438948
0.23743017 1.0541381
0.41283235 1.3774344
0.2761712 1.422105
-0.080429204 1.0753438
-0.5188592 0.956809
0.713986 0.99444
0.6536175 0.99848217
0.46903017 1.2054675
0.15473464 1.0716856
-0.28156337 0.8924131
0.5111026 0.67220867
0.42682606 0.89100254
0.4112979 0.7673037
0.07900778 0.74212146
-0.2720577 0.4557632
-0.4981358 1.4435326
-0.051663946 1.0917244
-0.023117686 0.5117782
-0.19846022 -0.042295564
-0.19126081 -0.3919759
0.29513282 1.3343437
0.93106616 1.0884248
0.9072645 0.5695666
0.5732627 0.095347434
0.26237917 -0.17561129
0.39974377 1.5594242
1.1159221 1.1927198
1.0814219 0.81222206
0.950581 0.10072425
0.671661 -0.01981995
0.48101172 1.4395866
1.0488389 1.4196151
1.003414 0.99251515
0.9169417 0.5299192
0.5284077 0.3711792
-0.20465238 1.7289668
0.40837994 1.5802932
0.26445296 1.4318615
0.16031574 0.9496403
0.18525025 0.90711755
-1.1795493 0.7756156
-1.0623146 1.6576271
-1.3544596 1.7558899
-1.3211613 1.423089
-1.4418778 1.063295
-1.2897592 0.9460997
-1.3648815 1.68862
-1.5633347 1.8560133
-1.4766223 1.7430701
-1.5375725 1.267287
-1.0636053 0.8309027
-1.0550519 1.4070404
-1.2028064 1.6903514
-1.3285335 1.5321271
-1.4901532 1.0099223
-0.59239966 0.26294753
-0.5102294 0.86975366
-0.7126663 0.8681627
-0.6390671 0.6666984
-0.88960606 0.39146528
0.11505768 -0.17483807
0.08690188 0.06906817
-0.012430734 0.0685056
-0.23703271 0.0048298114
-0.070601396 -0.29763746
-2.499217 -0.72470987
-1.5118762 -0.3025738
-0.63362616 0.1441088
0.34636214 0.6175989
0.80023897 0.71524495
-2.2490098 -0.08114317
-1.210647 0.23537244
-0.30495015 0.65833175
0.6582943 0.748487
0.92495674 0.7920688
-1.949688 0.08497454
-0.931986 0.5255702
0.08990933 0.82396054
0.8216611 1.130095
0.81956995 0.9759796
-1.0822672 0.31005707
-0.17065391 0.51547265
0.52672815 0.85156286
0.6972465 0.89206517
0.6062274 0.5910351
-0.1929201 0.28886735
0.5915268 0.5871289
0.72986585 0.55338776
0.88998604 0.54379845
0.5383484 0.27539033
0.69495237 1.3043873
0.8119897 2.1130838
1.0762402 2.00019
1.4192832 1.9147623
1.67176 1.2632021
0.63202345 1.6259333
0.958035 2.4304924
1.1269803 2.4733207
1.2325205 2.0936246
1.1469792 1.3039585
0.7853533 1.5398262
1.0906031 2.1048331
1.1132238 2.2389119
1.087981 1.5818008
1.0139153 0.94920427
1.3069341 1.1412464
1.2574402 1.5037223
1.2478752 1.2156814
1.1044679 1.0366565
0.7778477 0.3966581
1.4372398 0.37856415
1.3009509 0.6628915
1.2459791 0.5291198
0.84846544 0.11434809
0.73138183 -0.09481559

View File

@@ -1,13 +1,13 @@
12 12
0.0336404 -0.6611704
0.81687707 1.472362
-0.088157885 -0.059240177
1.072176 0.6448027
-0.019678842 -0.09498331
-0.23005776 0.07005496
2.6509802 1.5227689
2.31109 1.6761788
2.8000503 1.3155555
-0.044337805 3.944478
-0.20568089 0.41402242
2.5650184 1.6400838

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,31 @@
20 30
-0.19178796 -0.7973528
-0.0275628 -0.16212165
0.45375344 -0.016621558
2.1090505 -0.010184621
-0.012145723 -0.02323284
0.2213703 -0.65347326
2.624133 0.3813474
-0.82816005 -0.01980829
0.25926802 0.014691165
-0.014570757 0.84623796
0.72068256 1.0044321
0.249013 0.9791296
2.195925 0.09865961
-0.014568891 0.32203308
-0.59766585 0.008520375
-0.020068042 -0.27646253
-0.05986349 -0.034938164
-1.3474371 -0.0024497542
-0.49981204 -0.035473134
0.6370428 0.28444487
-0.7223666
-0.43071944
-0.27131405
0.18943691
-0.7551859
0.22790527
-0.19145727
0.3364544
0.8732161
0.93184555

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,16 @@
15 15
1.8846483 0.74399966
0.426767 0.65725124
-0.43499732 0.28723997
-0.86950755 -0.28500625
-1.4404491 -0.6551816
-1.6620952 -0.5096106
0.43332458 0.6995224
-0.047994245 0.47489655
-0.8123727 -0.637414
0.097763464 -0.14589947
-0.61916274 -0.6946489
0.20783848 0.06361784
-1.0543438 -0.9587668
0.42724028 0.33230728
0.7927464 0.01565033

View File

@@ -1,302 +1,452 @@
20 30
15 15
3.1785574e-34 0.01272495
1.5611281e-34 -0.10762496
-1.5863359e-34 0.029348347
-2.1766939e-34 0.043351036
-2.3130055e-34 0.014999958
-2.662751e-34 -0.06224802
-3.2626066e-34 -0.023997843
2.8627675e-34 0.02832638
2.7861122e-34 -0.041784886
-2.9668104e-34 0.0986206
3.0360296e-34 0.071423925
2.9419657e-34 0.071765825
3.1102713e-34 -0.0512679
-2.8726263e-34 -0.044301357
3.0484892e-34 -0.013093688
4.3197746e-34 -0.11556479
-1.8445088e-34 0.03982802
-3.530525e-34 0.09731361
-3.5233124e-34 0.00295955
2.2262768e-34 -0.03545694
1.2378974e-34 -0.006381662
3.7615624e-34 0.02806398
-2.2716454e-34 0.0045560263
2.5169786e-34 0.05397426
-3.353324e-34 0.03402133
3.5685113e-34 -0.036305163
-4.122433e-34 -0.043878928
1.7969215e-34 -0.0142929
5.2897058e-34 0.017667498
2.3318663e-34 -0.025763642
0.022835148 4.463302e-34
-0.029413782 7.2691345e-34
-0.12952074 8.845337e-34
0.18896067 1.0892352e-33
-0.06554771 4.7136717e-34
0.11628288 8.0413215e-35
-0.06948121 9.200099e-34
-0.025129182 -4.0106226e-36
0.009227986 4.1104475e-34
-0.10632306 5.224466e-35
0.21482462 2.8301181e-34
-0.09871392 -8.116642e-34
0.089015536 -3.1305442e-34
-0.008572652 -2.6887943e-34
-0.028414002 -2.190287e-34
0.08512151 -1.0852689e-33
-0.21057208 -3.8716697e-34
0.12899724 -3.4582993e-34
-0.121678144 4.0845394e-34
-0.044324484 -4.580933e-34
0.012617375 -5.545946e-34
0.23971003 -6.0027574e-34
-0.029345443 8.783881e-34
-0.10093057 1.1282351e-33
0.13569276 2.8688931e-34
-0.05262047 -6.931309e-34
-0.057448562 -7.412748e-34
-0.057186298 6.843897e-34
0.22441685 -1.07383705e-33
-0.09055193 -4.422186e-34
-2.5289643e-34 4.9493538e-34
1.7009551e-34 -3.3879648e-34
-3.9381888e-36 -2.5583285e-34
2.326881e-34 -9.684053e-38
-2.8111998e-34 1.1755804e-33
-3.5335243e-35 5.0118e-34
-1.1998445e-34 -6.8979133e-35
-3.4805974e-34 5.570329e-34
1.8599213e-34 2.0730477e-34
-1.7831123e-34 -6.9826827e-35
1.1460405e-34 1.7651477e-34
2.0934657e-34 6.505341e-34
1.563032e-34 1.1404848e-33
-1.0113456e-35 3.768194e-36
2.4719906e-35 -8.696617e-34
-0.12601055 1.6646721e-33
0.19141342 1.5833977e-33
-0.069146484 -1.16577035e-33
-0.0025679446 1.3946439e-33
-0.11021721 -1.6903357e-33
-0.047209635 1.18764e-33
0.121572815 -1.4414919e-33
-0.021320255 1.4874023e-33
0.17498343 -1.4271845e-33
-0.07666946 -1.5428872e-33
-0.03474931 -1.5855378e-33
-0.053848345 -1.5143901e-33
0.038261224 1.4189191e-33
0.09783123 -1.4440388e-33
-0.04364654 1.333818e-33
0.2465007 0.17302258
0.1849186 -0.027978221
-0.052974403 0.016748061
-0.064460956 -0.059101477
-0.0467655 -0.02370323
-0.036299426 0.055812847
-0.08964782 -0.027396126
-0.022229096 0.0083711
0.20783813 -0.019884026
-0.08701921 -0.02066343
-0.021651257 -0.005153278
-0.007302513 -0.010312685
-0.08308651 0.029041208
-0.07215878 -0.050187044
-0.0007826862 -0.024670767
-6.1247035e-34 -2.6037262e-33
4.463276e-34 -2.611591e-33
5.4647075e-34 2.4881792e-33
-5.3594374e-34 2.7212167e-33
-7.624689e-35 -2.5234833e-33
4.547081e-34 -2.2103461e-33
-4.9066397e-34 1.9122722e-33
-3.6748373e-34 9.588927e-34
-5.033634e-34 2.7108281e-33
5.2652385e-34 -2.3352854e-33
-5.817056e-34 -2.7606323e-33
-4.3149362e-34 -2.5427623e-33
5.304378e-34 2.6146137e-33
5.2734927e-34 2.4776098e-33
4.9347583e-34 2.5404514e-33
0.057774916 0.06246555
0.091525115 0.10426002
0.14736745 -0.052243777
0.13339345 0.017077662
0.15654251 -0.03715354
0.09139076 -0.018698398
0.12214476 -0.06796197
0.106167495 0.03528635
-0.1375304 0.06418046
-0.11402692 -0.000768907
-0.07316204 -0.026170308
-0.08932755 -0.019549962
-0.11316809 0.054662388
-0.10894508 -0.044521194
-0.12546284 -0.07334332
-3.2000347e-34 0.04758694
-2.36952e-34 -0.08954524
-2.2271435e-34 0.09964462
2.732874e-34 -0.031682633
-2.5469592e-34 -0.015182594
2.4332584e-34 -0.039172467
2.4015109e-34 0.07632043
2.305403e-34 -0.01974726
-1.0759744e-34 -0.08796382
1.7449821e-34 0.087372005
-2.3276338e-34 -0.016114255
-1.6425085e-34 -0.025341872
2.3379538e-34 -0.021241697
-1.2265797e-35 0.075716406
-2.2131944e-34 -0.027058382
-0.007536282 -0.015432766
-0.015670829 0.0073655327
-0.044145193 -0.01209919
-0.06925844 -0.041824125
-0.038289294 -0.006816338
0.04218386 0.0045526098
-0.028006999 -0.0005398891
0.19194373 0.13293515
-0.008162281 -0.014088044
-0.04310273 -0.04277335
-0.032295864 -0.046146225
-0.013634144 -0.011611434
0.012049367 -0.013375685
-0.04765994 -0.017687852
0.15002576 0.099150814
0.028484903 0.035996642
-0.12657242 0.016294181
-0.10019828 -0.08048032
-0.021912435 -0.041648608
-0.07220948 -0.012340834
-0.07850285 -0.024473786
-0.11347996 0.16153657
-0.084765114 -0.026676055
0.099906415 0.04658439
0.07358634 -0.052000005
0.085178904 -0.026849354
0.04134392 -0.03671153
0.09367139 -0.03710232
0.11517161 0.1337519
0.15800452 -0.031022256
0.2303931 -0.01850948
-0.04586972 0.01128599
-0.08725446 0.090702474
-0.033236336 -0.008731814
0.1308958 -0.00024545888
-0.036943685 -0.010025267
-0.014320934 -0.039491266
-0.0052397517 -0.020047752
-0.013388744 0.034077633
-0.024721963 0.019151518
-0.05172364 -0.017094668
0.03730736 -0.01866218
-0.02536234 -0.017035574
-0.04374987 0.005504165
-0.033061035 -0.0069074775
-0.0024779101 -0.00089758425
0.000728523 -0.0016957085
3.03098e-06 0.00025294858
-0.0006537406 -0.002470556
0.0014257621 -0.00253977
7.1307574e-07 -0.0026819948
2.82788e-05 -0.001282234
-1.4571673e-08 -0.0027133073
-9.1665876e-05 0.0060566748
-0.0005169288 -0.0017536315
-0.00088055246 -0.0004967247
0.0009669605 -0.004892902
0.0002642583 0.0044350573
7.58049e-06 -0.0026093745
5.0228886e-05 0.003550591
4.1370527e-34 0.04047877
-2.3665282e-34 0.05901869
2.6231246e-34 0.043092217
3.7994393e-34 0.08706535
4.0085556e-34 0.077308305
-2.6690339e-34 0.044446126
1.8781805e-34 0.051501554
-1.982984e-34 0.017045613
-3.0113217e-34 -0.056876663
-2.1200167e-34 -0.051144525
-2.0077406e-35 -0.050281346
3.0132427e-34 -0.011186705
-3.0806865e-34 -0.055486917
-1.9560212e-34 -0.0782539
1.2020748e-34 -0.0805333
4.1127485e-34 -0.043732617
-3.2173455e-34 -0.0068375436
4.0228943e-34 -0.03201547
-3.1162013e-34 -0.059948742
-5.1426757e-34 0.05957991
2.6755438e-34 0.067795284
3.6094879e-34 -0.04184092
-4.8759634e-34 0.004160195
3.4464383e-34 0.008685335
-2.8995517e-34 -0.054342967
-3.1393783e-34 -0.033768225
-2.2658088e-34 0.11686653
-3.3108237e-34 0.081372775
-1.3505708e-35 -0.017015154
2.4738205e-34 -0.023423227
3.783955e-34 8.78021e-34
3.6061226e-34 8.345785e-34
3.193828e-34 7.4883407e-34
3.7868991e-34 8.48771e-34
3.6567402e-34 8.274504e-34
-3.0349225e-34 8.027745e-34
3.3677782e-34 8.773579e-34
2.8857424e-34 8.519454e-34
2.5269046e-34 -8.11835e-34
2.2737943e-34 -7.688669e-34
-2.65504e-34 8.082543e-34
-2.732385e-34 -7.3258576e-34
2.6953094e-34 -8.51516e-34
2.9642443e-34 7.221161e-34
2.6588915e-34 7.827067e-34
-0.07233555 1.2615198e-33
-0.030644806 1.0976719e-33
0.014339875 1.1967251e-33
0.010646929 -1.0436973e-33
0.15107094 -8.499446e-34
-0.04039454 2.2683726e-34
-0.1018803 -1.3970104e-33
-0.024136122 1.5193663e-33
0.013392502 1.2094788e-33
-0.0011950728 -1.133173e-33
0.06232135 -1.2547036e-33
0.20024493 -1.4050951e-33
-0.06713317 -1.4054403e-33
-0.08364978 -1.142544e-33
-0.010007126 1.0450027e-33
0.073318966 7.6956433e-34
0.0020213877 8.744477e-34
0.015295026 -3.8514544e-35
-0.09381448 4.8746516e-34
0.018438634 -9.3443655e-34
0.15810835 -1.3859844e-34
-0.122952715 -1.2412909e-34
-0.06948898 -1.6619894e-34
-0.03245277 -1.0620242e-33
-0.07937658 1.4781585e-34
-0.074316666 -7.03722e-34
0.14917618 6.034873e-34
0.21517377 4.964442e-34
-0.07048892 6.136231e-34
-0.060168184 8.249319e-34
0.02568059 0.008318748
-0.04876075 0.041124124
0.19848819 -0.016857537
0.073280066 -0.04932119
-0.09127431 -0.0122754285
-0.040448762 0.10398687
-0.11075618 -0.015096632
-0.0018404849 -0.0022395186
-0.04922203 -0.015617358
0.22584344 0.036401253
0.08676703 -0.060664278
0.023621265 0.010920629
-0.02429366 0.053897887
-0.13942361 -0.030621164
-0.047222435 -0.030898456
-0.032895576
-0.102701336
-0.026651151
0.11469333
-0.063634604
0.06844623
-0.018467609
0.00821091
-0.07843062
-0.0055042044
0.090303816
-0.046396058
0.075963
0.03063942
0.020872513
-0.01299387
-0.0037207452
-0.0242024
0.06550928
-0.024706954
0.014491363
-0.011790568
-0.0025269324
-0.004879747
-0.030484857
0.0600873
-0.023517173
0.03269997
0.0051519005
-0.012163694
1.1904957e-33
1.0479699e-33
5.779416e-34
1.1540947e-33
-9.659636e-34
-1.0160334e-33
-8.223222e-34
8.918577e-34
1.0935816e-33
-9.294705e-34
-1.1592887e-33
9.246344e-34
1.180318e-33
-9.126836e-34
1.1287711e-33
0.026146693
0.09916242
-0.043090336
0.0017119434
0.0016878549
-0.017987054
-0.049805358
-0.022761522
0.092246346
-0.040928245
0.06459246
-0.017492786
-0.0049494132
-0.04219089
-0.03418938
-1.7006182e-33
-1.4530463e-33
1.42898475e-33
1.5074225e-33
-1.3642416e-33
-1.4290173e-33
1.4108531e-33
-1.2353524e-33
1.5234947e-33
-1.3775423e-33
1.4153025e-33
1.3714305e-33
-1.484371e-33
-1.44253985e-33
1.3046794e-33
0.044514116
-0.000882356
-0.0096916985
-0.04236413
0.091675386
-0.023483241
0.014011558
-0.004130279
-0.036856808
-0.033731807
-0.012403026
0.002606612
0.017260972
0.015992519
-0.015452466
0.07528171
-0.021592995
-0.06897829
0.0042408453
-0.027098294
-0.06743852
-0.09114424
-0.10261911
0.10710511
0.049893394
0.059722904
0.04513747
0.053101413
0.041433763
0.09596609
0.09589958
-0.025171956
-0.0013778559
-0.016897377
-0.022183804
-0.00023300173
-0.0065004122
0.0055662235
-0.014621925
0.0004447254
0.00226211
-0.011209562
-0.0183207
-0.011526959
0.005361926
0.17491823
-0.018875118
0.03126051
-0.039963342
-0.033307772
0.0015879893
-0.041357704
-0.0036194928
-0.03158664
-0.004237409
-0.034398682
-0.017561572
0.023918597
-0.0046276804
-0.011843316
0.023838982
0.11698544
-0.036167253
-0.019597769
-0.012699235
-0.012540517
-0.03393306
-0.0059446017
-0.00016750683
0.0014437584
-0.0015821535
-0.0019046782
-0.0021211132
-0.02051653
-0.008041249