Compare commits
16 Commits
41a31f1c18
...
NUC3.28
| Author | SHA1 | Date | |
|---|---|---|---|
| 9104d65bb2 | |||
| 460ef760fa | |||
| 12a02f382a | |||
| 3eb2d39942 | |||
| c0ee469118 | |||
| a133dea09a | |||
| 15be04d1f7 | |||
|
|
7770503779 | ||
|
|
5cf1a30ea0 | ||
|
|
7f6e2f4e6e | ||
|
|
0b1f5ff47f | ||
|
|
e1eb8b2590 | ||
|
|
b24542e97c | ||
|
|
de94ff2242 | ||
|
|
d5df7ce7da | ||
|
|
ef257b7df0 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,6 +1,9 @@
|
||||
cmake-build-debug
|
||||
build
|
||||
.idea
|
||||
.xmake
|
||||
.vscode/.cache
|
||||
.vscode/compile_commands.json
|
||||
Mark
|
||||
armor_box_photo
|
||||
tools/TrainCNN/.idea
|
||||
@@ -9,4 +12,4 @@ tools/TrainCNN/__pycache__
|
||||
others/include/config/config.h
|
||||
others/MV-UB31-Group0.config
|
||||
.DS_Store
|
||||
video
|
||||
video
|
||||
|
||||
8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"clangd.arguments": [
|
||||
"--compile-commands-dir=${workspaceFolder}/build",
|
||||
"--completion-style=detailed",
|
||||
"--query-driver=/usr/bin/clang",
|
||||
"--header-insertion=never"
|
||||
],
|
||||
}
|
||||
@@ -8,6 +8,8 @@ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPATH=\"\\\"${PROJECT_SOURCE_DIR}\\\"\"
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${CMAKE_SYSTEM_NAME}")
|
||||
SET(BIN_NAME "run")
|
||||
|
||||
SET(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
|
||||
FIND_FILE(CONFIG_FOUND "config.h" "others/include/config")
|
||||
if (CONFIG_FOUND)
|
||||
@@ -24,7 +26,7 @@ IF(CCACHE_FOUND)
|
||||
ENDIF()
|
||||
|
||||
FIND_PACKAGE(Eigen3 REQUIRED)
|
||||
FIND_PACKAGE(OpenCV 3 REQUIRED)
|
||||
FIND_PACKAGE(OpenCV 4 REQUIRED)
|
||||
FIND_PACKAGE(Threads)
|
||||
|
||||
LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/others)
|
||||
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 xinyang
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
12
README.md
12
README.md
@@ -13,6 +13,12 @@
|
||||
|
||||
**如有BUG或者想交流的朋友欢迎积极联系我们**
|
||||
|
||||
**分享部分比赛时摄像头录制的视频:**
|
||||
|
||||
链接: https://pan.baidu.com/s/1LwxEpeYYblX3cSzb59MTVg 提取码: 84ju 复制这段内容后打开百度网盘手机App,操作更方便哦
|
||||
|
||||
---
|
||||
|
||||
运行效果:自瞄帧率120(摄像头最大帧率),识别距离根据环境不同大约8米左右(5mm焦距镜头)。
|
||||
|
||||

|
||||
@@ -24,6 +30,8 @@
|
||||
| ---------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------- |
|
||||
| IntelNUC<br />MindVision工业相机×1<br />USB转TTL×1 | Ubuntu18.04<br />Ubuntu16.04<br />Windows10 | OpenCV3.4.5<br />OpenCV_contrib3.4.5<br />Eigen3<br />MindVision相机驱动 | Ubuntu18/16 : cmake3+gcc7+g++7 <br />Win10 : cmake3+VS2019 |
|
||||
|
||||
MindVision相机型号:MV-UBS31GC
|
||||
|
||||
**关于Windows环境下的运行支持,仅保证程序可以编译运行。对与部分辅助功能,如生成自启动脚本则不支持。**
|
||||
|
||||
**实际装载在步兵和哨兵上的运行环境为Ubuntu18.04。**
|
||||
@@ -60,6 +68,8 @@ sudo ./run
|
||||
|
||||
```./run --help```可以查看所有命令行参数及其作用。所有调试选项都集成到了命令行参数中。
|
||||
|
||||
**不使用任何参数直接运行将没有任何图像显示。**
|
||||
|
||||
需要调参的部分:主要需要根据车辆情况而调参的参数存放在others/include/config/setconfig.h中
|
||||
|
||||
### 3.工作条件
|
||||
@@ -118,7 +128,7 @@ sudo ./run
|
||||
### 1.自瞄装甲板识别方式
|
||||
|
||||
首先对图像进行通道拆分以及二值化操作,再进行开闭运算,通过边缘提取和条件限制得出可能为灯条的部分。再对所有可能的灯条进行两两匹配,根据形状大小特性进行筛选,得出可能为装甲板的候选区。然后把所有候选区交给分类器判断,得出真实的装甲板及其数字id。最后根据优先级选取最终击打目标以及后续处理。
|
||||
|
||||

|
||||
### 2.能量机关识别方式
|
||||
|
||||
首先对图像进行二值化操作,然后进行一定腐蚀和膨胀,通过边缘提取和条件限制得出待击打叶片(锤子形)。在待击打叶片范围内进一步用类似方法寻找目标装甲板和流动条,在二者连线上寻找中心的“R”。根据目标装甲板坐标和中心坐标计算极坐标系下的目标角度,进而预测待击打点的坐标(小符为装甲板本身,大符需要旋转)。最后将待击打点坐标和图像中心的差值转换为yaw和pitch轴角度,增加一环PID后发送给云台主控板。
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <systime.h>
|
||||
#include <constants.h>
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/tracking.hpp>
|
||||
#include <opencv2/tracking/tracking.hpp>
|
||||
#include <serial.h>
|
||||
#include <armor_finder/classifier/classifier.h>
|
||||
#include <additions.h>
|
||||
@@ -20,8 +20,8 @@
|
||||
#define BOX_RED ENEMY_RED
|
||||
#define BOX_BLUE ENEMY_BLUE
|
||||
|
||||
#define IMAGE_CENTER_X (320)
|
||||
#define IMAGE_CENTER_Y (240-20)
|
||||
#define IMAGE_CENTER_X (640)
|
||||
#define IMAGE_CENTER_Y (512-20)
|
||||
|
||||
#define DISTANCE_HEIGHT_5MM (10700.0) // 单位: cm*pixel
|
||||
#define DISTANCE_HEIGHT DISTANCE_HEIGHT_5MM
|
||||
@@ -120,6 +120,10 @@ private:
|
||||
vector<systime> time_seq; // 一个周期内的时间采样点
|
||||
vector<float> angle_seq; // 一个周期内的角度采样点
|
||||
|
||||
float yaw_rotation, pitch_rotation;//云台yaw轴和pitch轴应该转到的角度
|
||||
float last_yaw, last_pitch;//PID中微分项
|
||||
float sum_yaw, sum_pitch;//yaw和pitch的累计误差,即PID中积分项
|
||||
|
||||
bool findLightBlobs(const cv::Mat &src, LightBlobs &light_blobs);
|
||||
bool findArmorBox(const cv::Mat &src, ArmorBox &box);
|
||||
bool matchArmorBoxes(const cv::Mat &src, const LightBlobs &light_blobs, ArmorBoxes &armor_boxes);
|
||||
|
||||
@@ -38,6 +38,14 @@ void ArmorFinder::antiTop() {
|
||||
// 通过两次装甲角度为零的时间差计算陀螺旋转周期
|
||||
// 根据旋转周期计算下一次装甲出现在角度为零的时间点
|
||||
if (getPointLength(last_box.getCenter() - target_box.getCenter()) > last_box.rect.height * 1.5) {
|
||||
/* PID相关控制 */
|
||||
sum_yaw = sum_pitch = 0;
|
||||
double dx = target_box.rect.x + target_box.rect.width / 2 - IMAGE_CENTER_X;
|
||||
double dy = target_box.rect.y + target_box.rect.height / 2 - IMAGE_CENTER_Y;
|
||||
double yaw = dx;
|
||||
double pitch = dy;
|
||||
/* PID相关控制 */
|
||||
|
||||
auto front_time = getFrontTime(time_seq, angle_seq);
|
||||
auto once_periodms = getTimeIntervalms(front_time, last_front_time);
|
||||
// if (abs(once_periodms - top_periodms[-1]) > 50) {
|
||||
|
||||
@@ -54,7 +54,11 @@ ArmorFinder::ArmorFinder(uint8_t &color, Serial &u, const string ¶s_folder,
|
||||
anti_switch_cnt(0),
|
||||
classifier(paras_folder),
|
||||
contour_area(0),
|
||||
tracking_cnt(0) {
|
||||
tracking_cnt(0),
|
||||
last_yaw(0),
|
||||
last_pitch(0),
|
||||
sum_yaw(0),
|
||||
sum_pitch(0) {
|
||||
}
|
||||
|
||||
void ArmorFinder::run(cv::Mat &src) {
|
||||
@@ -67,7 +71,7 @@ void ArmorFinder::run(cv::Mat &src) {
|
||||
if ((target_box.rect & cv::Rect2d(0, 0, 640, 480)) == target_box.rect) { // 判断装甲板区域是否脱离图像区域
|
||||
if (!classifier) { /* 如果分类器不可用 */
|
||||
cv::Mat roi = src(target_box.rect).clone(), roi_gray; /* 就使用装甲区域亮点数判断是否跟丢 */
|
||||
cv::cvtColor(roi, roi_gray, CV_RGB2GRAY);
|
||||
cv::cvtColor(roi, roi_gray, cv::COLOR_RGB2GRAY);
|
||||
cv::threshold(roi_gray, roi_gray, 180, 255, cv::THRESH_BINARY);
|
||||
contour_area = cv::countNonZero(roi_gray);
|
||||
}
|
||||
@@ -75,6 +79,9 @@ void ArmorFinder::run(cv::Mat &src) {
|
||||
tracker->init(src, target_box.rect);
|
||||
state = TRACKING_STATE;
|
||||
tracking_cnt = 0;
|
||||
last_yaw = target_box.rect.x + target_box.rect.width / 2 - IMAGE_CENTER_X;
|
||||
last_pitch = target_box.rect.y + target_box.rect.height / 2 - IMAGE_CENTER_Y;
|
||||
sum_yaw = sum_pitch = 0;
|
||||
LOGM(STR_CTR(WORD_LIGHT_CYAN, "into track"));
|
||||
}
|
||||
}
|
||||
@@ -82,6 +89,8 @@ void ArmorFinder::run(cv::Mat &src) {
|
||||
case TRACKING_STATE:
|
||||
if (!stateTrackingTarget(src) || ++tracking_cnt > 100) { // 最多追踪100帧图像
|
||||
state = SEARCHING_STATE;
|
||||
last_yaw = last_pitch = 0;
|
||||
sum_yaw = sum_pitch = 0;
|
||||
LOGM(STR_CTR(WORD_LIGHT_YELLOW, "into search!"));
|
||||
}
|
||||
break;
|
||||
@@ -93,6 +102,11 @@ end:
|
||||
if(is_anti_top) { // 判断当前是否为反陀螺模式
|
||||
antiTop();
|
||||
}else if(target_box.rect != cv::Rect2d()) {
|
||||
if(last_box.rect == cv::Rect2d()) { // 如果上一帧没有目标装甲板
|
||||
sum_yaw = sum_pitch = 0;
|
||||
last_yaw = target_box.rect.x + target_box.rect.width / 2 - IMAGE_CENTER_X;
|
||||
last_pitch = target_box.rect.y + target_box.rect.height / 2 - IMAGE_CENTER_Y;
|
||||
}
|
||||
anti_top_cnt = 0;
|
||||
time_seq.clear();
|
||||
angle_seq.clear();
|
||||
|
||||
@@ -156,6 +156,7 @@ bool ArmorFinder::findArmorBox(const cv::Mat &src, ArmorBox &box) {
|
||||
for (auto &one_box : armor_boxes) {
|
||||
if (one_box.id != 0) {
|
||||
box = one_box;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (save_labelled_boxes) {
|
||||
|
||||
@@ -83,11 +83,11 @@ bool ArmorFinder::findLightBlobs(const cv::Mat &src, LightBlobs &light_blobs) {
|
||||
}else{
|
||||
light_threshold = 200;
|
||||
}
|
||||
cv::threshold(color_channel, src_bin_light, light_threshold, 255, CV_THRESH_BINARY); // 二值化对应通道
|
||||
cv::threshold(color_channel, src_bin_light, light_threshold, 255, cv::THRESH_BINARY); // 二值化对应通道
|
||||
if (src_bin_light.empty()) return false;
|
||||
imagePreProcess(src_bin_light); // 开闭运算
|
||||
|
||||
cv::threshold(color_channel, src_bin_dim, 140, 255, CV_THRESH_BINARY); // 二值化对应通道
|
||||
cv::threshold(color_channel, src_bin_dim, 140, 255, cv::THRESH_BINARY); // 二值化对应通道
|
||||
if (src_bin_dim.empty()) return false;
|
||||
imagePreProcess(src_bin_dim); // 开闭运算
|
||||
|
||||
@@ -100,8 +100,8 @@ bool ArmorFinder::findLightBlobs(const cv::Mat &src, LightBlobs &light_blobs) {
|
||||
std::vector<std::vector<cv::Point>> light_contours_light, light_contours_dim;
|
||||
LightBlobs light_blobs_light, light_blobs_dim;
|
||||
std::vector<cv::Vec4i> hierarchy_light, hierarchy_dim;
|
||||
cv::findContours(src_bin_light, light_contours_light, hierarchy_light, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
|
||||
cv::findContours(src_bin_dim, light_contours_dim, hierarchy_dim, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
|
||||
cv::findContours(src_bin_light, light_contours_light, hierarchy_light, cv::RETR_CCOMP, cv::CHAIN_APPROX_NONE);
|
||||
cv::findContours(src_bin_dim, light_contours_dim, hierarchy_dim, cv::RETR_CCOMP, cv::CHAIN_APPROX_NONE);
|
||||
for (int i = 0; i < light_contours_light.size(); i++) {
|
||||
if (hierarchy_light[i][2] == -1) {
|
||||
cv::RotatedRect rect = cv::minAreaRect(light_contours_light[i]);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <log.h>
|
||||
|
||||
static bool sendTarget(Serial &serial, double x, double y, double z, uint16_t shoot_delay) {
|
||||
|
||||
static short x_tmp, y_tmp, z_tmp;
|
||||
uint8_t buff[10];
|
||||
|
||||
@@ -22,9 +23,12 @@ static bool sendTarget(Serial &serial, double x, double y, double z, uint16_t sh
|
||||
fps += 1;
|
||||
#endif
|
||||
|
||||
x_tmp = static_cast<short>(x * (32768 - 1) / 100);
|
||||
#define MINMAX(value, min, max) value = ((value) < (min)) ? (min) : ((value) > (max) ? (max) : (value))
|
||||
|
||||
x_tmp = -static_cast<short>(x * (32768 - 1) / 100);
|
||||
y_tmp = static_cast<short>(y * (32768 - 1) / 100);
|
||||
z_tmp = static_cast<short>(z * (32768 - 1) / 1000);
|
||||
|
||||
|
||||
buff[0] = 's';
|
||||
buff[1] = static_cast<char>((x_tmp >> 8) & 0xFF);
|
||||
@@ -36,19 +40,51 @@ static bool sendTarget(Serial &serial, double x, double y, double z, uint16_t sh
|
||||
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;
|
||||
//if(buff[7]<<8 | buff[8])
|
||||
// cout << (buff[7]<<8 | buff[8]) << endl;
|
||||
return serial.WriteData(buff, sizeof(buff));
|
||||
|
||||
|
||||
// Vofa串口验证
|
||||
|
||||
//char buff[128];
|
||||
//int len = (buff, "s %lf %lf %lf %d e", x, y, z, shoot_delay);
|
||||
//return serial.WriteData((unsigned char *)buff, len);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool ArmorFinder::sendBoxPosition(uint16_t shoot_delay) {
|
||||
if (target_box.rect == cv::Rect2d()) return false;
|
||||
if (shoot_delay) {
|
||||
/*if (shoot_delay) {
|
||||
LOGM(STR_CTR(WORD_BLUE, "next box %dms"), shoot_delay);
|
||||
}
|
||||
}*/
|
||||
auto rect = target_box.rect;
|
||||
double dx = rect.x + rect.width / 2 - IMAGE_CENTER_X;
|
||||
double dy = rect.y + rect.height / 2 - IMAGE_CENTER_Y;
|
||||
|
||||
// PID
|
||||
#define MAX_YAW 100
|
||||
#define MAX_PITCH 80
|
||||
sum_yaw += dx;
|
||||
sum_pitch += dy;
|
||||
sum_yaw =(sum_yaw > MAX_YAW) ? MAX_YAW : (sum_yaw < -MAX_YAW ? -MAX_YAW : sum_yaw);
|
||||
sum_pitch =(sum_pitch > MAX_PITCH) ? MAX_PITCH : (sum_pitch < -MAX_PITCH ? -MAX_PITCH : sum_pitch);
|
||||
float yaw_I_component = YAW_AIM_KI * sum_yaw;
|
||||
float pitch_I_component = PITCH_AIM_KI * sum_pitch;
|
||||
|
||||
double tmp_yaw = dx;
|
||||
double tmp_pitch = dy;
|
||||
dx = YAW_AIM_KP * dx + YAW_AIM_KI * sum_yaw +
|
||||
YAW_AIM_KD * (dx - last_yaw);
|
||||
dy = PITCH_AIM_KP * dy + PITCH_AIM_KI * sum_pitch +
|
||||
PITCH_AIM_KD * (dy - last_pitch);
|
||||
|
||||
last_yaw = tmp_yaw;
|
||||
last_pitch = tmp_pitch;
|
||||
//
|
||||
|
||||
double yaw = atan(dx / FOCUS_PIXAL) * 180 / PI;
|
||||
double pitch = atan(dy / FOCUS_PIXAL) * 180 / PI;
|
||||
double dist = DISTANCE_HEIGHT / rect.height;
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
#include <show_images/show_images.h>
|
||||
|
||||
bool ArmorFinder::stateTrackingTarget(cv::Mat &src) {
|
||||
auto pos = target_box.rect;
|
||||
cv::Rect pos(target_box.rect);
|
||||
if(!tracker->update(src, pos)){ // 使用KCFTracker进行追踪
|
||||
target_box = ArmorBox();
|
||||
LOGW("Track fail!");
|
||||
return false;
|
||||
}
|
||||
if((pos & cv::Rect2d(0, 0, 640, 480)) != pos){
|
||||
if((cv::Rect2d(pos) & cv::Rect2d(0, 0, 640, 480)) != cv::Rect2d(pos)){
|
||||
target_box = ArmorBox();
|
||||
LOGW("Track out range!");
|
||||
return false;
|
||||
@@ -52,7 +52,7 @@ bool ArmorFinder::stateTrackingTarget(cv::Mat &src) {
|
||||
}
|
||||
}else{ // 分类器不可用,使用常规方法判断
|
||||
cv::Mat roi_gray;
|
||||
cv::cvtColor(roi, roi_gray, CV_RGB2GRAY);
|
||||
cv::cvtColor(roi, roi_gray, cv::COLOR_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){
|
||||
|
||||
@@ -21,12 +21,12 @@ int Energy::findFans(const cv::Mat &src) {
|
||||
static Mat src_bin;
|
||||
src_bin = src.clone();
|
||||
if (src.type() == CV_8UC3) {
|
||||
cvtColor(src_bin, src_bin, CV_BGR2GRAY);//若读取三通道视频文件,需转换为单通道
|
||||
cvtColor(src_bin, src_bin, cv::COLOR_BGR2GRAY);//若读取三通道视频文件,需转换为单通道
|
||||
}
|
||||
std::vector<vector<Point> > fan_contours;
|
||||
FanStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找
|
||||
if (show_process)imshow("fan struct", src_bin);
|
||||
findContours(src_bin, fan_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
|
||||
findContours(src_bin, fan_contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
|
||||
|
||||
for (auto &fan_contour : fan_contours) {
|
||||
if (!isValidFanContour(src_bin, fan_contour)) {
|
||||
@@ -54,16 +54,16 @@ int Energy::findArmors(const cv::Mat &src) {
|
||||
static Mat src_bin;
|
||||
src_bin = src.clone();
|
||||
if (src.type() == CV_8UC3) {
|
||||
cvtColor(src_bin, src_bin, CV_BGR2GRAY);//若读取三通道视频文件,需转换为单通道
|
||||
cvtColor(src_bin, src_bin, cv::COLOR_BGR2GRAY);//若读取三通道视频文件,需转换为单通道
|
||||
}
|
||||
std::vector<vector<Point> > armor_contours;
|
||||
std::vector<vector<Point> > armor_contours_external;//用总轮廓减去外轮廓,只保留内轮廓,除去流动条的影响。
|
||||
|
||||
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);
|
||||
if (show_process)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++)//去除外轮廓
|
||||
{
|
||||
unsigned long external_contour_size = armor_contours_external[i].size();
|
||||
@@ -103,12 +103,12 @@ bool Energy::findCenterR(const cv::Mat &src) {
|
||||
static Mat src_bin;
|
||||
src_bin = src.clone();
|
||||
if (src.type() == CV_8UC3) {
|
||||
cvtColor(src_bin, src_bin, CV_BGR2GRAY);
|
||||
cvtColor(src_bin, src_bin, cv::COLOR_BGR2GRAY);
|
||||
}
|
||||
std::vector<vector<Point> > center_R_contours;
|
||||
CenterRStruct(src_bin);
|
||||
if (show_process)imshow("R struct", src_bin);
|
||||
findContours(src_bin, center_R_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
|
||||
findContours(src_bin, center_R_contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
|
||||
for (auto ¢er_R_contour : center_R_contours) {
|
||||
if (!isValidCenterRContour(center_R_contour)) {
|
||||
continue;
|
||||
@@ -139,13 +139,13 @@ bool Energy::findFlowStripFan(const cv::Mat &src) {
|
||||
src_bin = src.clone();
|
||||
src_copy = src.clone();
|
||||
if (src.type() == CV_8UC3) {
|
||||
cvtColor(src_bin, src_bin, CV_BGR2GRAY);//若读取三通道视频文件,需转换为单通道
|
||||
cvtColor(src_bin, src_bin, cv::COLOR_BGR2GRAY);//若读取三通道视频文件,需转换为单通道
|
||||
}
|
||||
std::vector<vector<Point> > flow_strip_fan_contours;
|
||||
FlowStripFanStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找
|
||||
if (show_process)imshow("flow strip fan struct", src_bin);
|
||||
|
||||
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);
|
||||
std::vector<cv::RotatedRect> candidate_flow_strip_fans;
|
||||
|
||||
for (auto &flow_strip_fan_contour : flow_strip_fan_contours) {
|
||||
@@ -175,7 +175,7 @@ bool Energy::findFlowStrip(const cv::Mat &src) {
|
||||
|
||||
if (src_bin.type() == CV_8UC1) // 黑白图像
|
||||
{
|
||||
cvtColor(src_bin, src_bin, COLOR_GRAY2RGB);
|
||||
cvtColor(src_bin, src_bin, cv::COLOR_GRAY2RGB);
|
||||
|
||||
}
|
||||
std::vector<cv::RotatedRect> candidate_target_armors = target_armors;
|
||||
@@ -189,13 +189,13 @@ bool Energy::findFlowStrip(const cv::Mat &src) {
|
||||
}
|
||||
}
|
||||
|
||||
cvtColor(src_bin, src_bin, CV_BGR2GRAY);//若读取三通道视频文件,需转换为单通道
|
||||
cvtColor(src_bin, src_bin, cv::COLOR_BGR2GRAY);//若读取三通道视频文件,需转换为单通道
|
||||
|
||||
FlowStripStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找
|
||||
if (show_process)imshow("flow strip struct", src_bin);
|
||||
|
||||
std::vector<vector<Point> > flow_strip_contours;
|
||||
findContours(src_bin, flow_strip_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
|
||||
findContours(src_bin, flow_strip_contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
|
||||
|
||||
for (auto candidate_flow_strip_fan: flow_strip_fans) {
|
||||
for (auto &flow_strip_contour : flow_strip_contours) {
|
||||
@@ -261,7 +261,7 @@ bool Energy::findFlowStripWeak(const cv::Mat &src) {
|
||||
|
||||
if (src_bin.type() == CV_8UC1) // 黑白图像
|
||||
{
|
||||
cvtColor(src_bin, src_bin, COLOR_GRAY2RGB);
|
||||
cvtColor(src_bin, src_bin, cv::COLOR_GRAY2RGB);
|
||||
|
||||
}
|
||||
std::vector<cv::RotatedRect> candidate_armors = armors;
|
||||
@@ -275,13 +275,13 @@ bool Energy::findFlowStripWeak(const cv::Mat &src) {
|
||||
}
|
||||
}
|
||||
|
||||
cvtColor(src_bin, src_bin, CV_BGR2GRAY);//若读取三通道视频文件,需转换为单通道
|
||||
cvtColor(src_bin, src_bin, cv::COLOR_BGR2GRAY);//若读取三通道视频文件,需转换为单通道
|
||||
|
||||
FlowStripStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找
|
||||
if (show_process)imshow("weak struct", src_bin);
|
||||
|
||||
std::vector<vector<Point> > flow_strip_contours;
|
||||
findContours(src_bin, flow_strip_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
|
||||
findContours(src_bin, flow_strip_contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
|
||||
|
||||
for (auto &flow_strip_contour : flow_strip_contours) {
|
||||
if (!isValidFlowStripContour(flow_strip_contour)) {
|
||||
@@ -335,6 +335,4 @@ bool Energy::findCenterROI(const cv::Mat &src) {
|
||||
Size2f(length * 1.7, length * 1.7), -90);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
4
main.cpp
4
main.cpp
@@ -44,7 +44,9 @@ WrapperHead *video = nullptr; // 云台摄像头视频源
|
||||
Serial serial(115200); // 串口对象
|
||||
uint8_t last_state = ARMOR_STATE; // 上次状态,用于初始化
|
||||
// 自瞄主程序对象
|
||||
ArmorFinder armor_finder(mcu_data.enemy_color, serial, PROJECT_DIR"/tools/para/", mcu_data.anti_top);
|
||||
uint8_t enemy_color = ENEMY_BLUE;//RED ro BLUE
|
||||
uint8_t forced_anti_top = 1;
|
||||
ArmorFinder armor_finder(enemy_color, serial, PROJECT_DIR"/tools/para/", forced_anti_top);
|
||||
// 能量机关主程序对象
|
||||
Energy energy(serial, mcu_data.enemy_color);
|
||||
|
||||
|
||||
@@ -5,17 +5,17 @@ resolution :
|
||||
image_size :
|
||||
{
|
||||
iIndex = 1;
|
||||
acDescription = "640X480 ROI";
|
||||
acDescription = "1280X1024 ROI";
|
||||
uBinSumMode = 0;
|
||||
uBinAverageMode = 0;
|
||||
uSkipMode = 0;
|
||||
uResampleMask = 0;
|
||||
iHOffsetFOV = 56;
|
||||
iVOffsetFOV = 0;
|
||||
iWidthFOV = 640;
|
||||
iHeightFOV = 480;
|
||||
iWidth = 640;
|
||||
iHeight = 480;
|
||||
iWidthFOV = 1280;
|
||||
iHeightFOV = 1024;
|
||||
iWidth = 1280;
|
||||
iHeight = 1024;
|
||||
iWidthZoomHd = 0;
|
||||
iHeightZoomHd = 0;
|
||||
iWidthZoomSw = 0;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -662,4 +662,4 @@ typedef void (*CAMERA_PAGE_MSG_PROC)(CameraHandle hCamera,UINT MSG,UINT uParam,P
|
||||
#define CAMERA_MEDIA_TYPE_RGB16_PLANAR (CAMERA_MEDIA_TYPE_COLOR | CAMERA_MEDIA_TYPE_OCCUPY48BIT | 0x0024)
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#define _CAMERA_WRAPPER_H_
|
||||
|
||||
#include <additions.h>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/core.hpp>
|
||||
#include <camera/wrapper_head.h>
|
||||
|
||||
#ifdef Windows
|
||||
@@ -19,9 +19,9 @@ class CameraWrapper: public WrapperHead {
|
||||
friend void cameraCallback(CameraHandle hCamera, BYTE *pFrameBuffer, tSdkFrameHead* pFrameHead,PVOID pContext);
|
||||
private:
|
||||
const std::string name;
|
||||
int mode;
|
||||
//int mode;
|
||||
|
||||
bool init_done;
|
||||
//bool init_done;
|
||||
|
||||
unsigned char* rgb_buffer;
|
||||
int camera_cnts;
|
||||
@@ -33,13 +33,16 @@ private:
|
||||
tSdkCameraCapbility tCapability;
|
||||
tSdkFrameHead frame_info;
|
||||
BYTE *pby_buffer;
|
||||
IplImage* iplImage;
|
||||
cv::Mat image_header;
|
||||
int channel;
|
||||
|
||||
RoundQueue<cv::Mat, 2> src_queue;
|
||||
public:
|
||||
int gain;
|
||||
int exposure;
|
||||
|
||||
int mode;
|
||||
bool init_done;
|
||||
|
||||
CameraWrapper(int exposure, int gain, int camera_mode=1, const std::string &n="NULL");
|
||||
~CameraWrapper() final;
|
||||
@@ -52,4 +55,4 @@ public:
|
||||
};
|
||||
|
||||
|
||||
#endif /* _CAMERA_WRAPPER_H_ */
|
||||
#endif /* _CAMERA_WRAPPER_H_ */
|
||||
@@ -4,6 +4,7 @@
|
||||
#ifndef _SETCONFIG_H_
|
||||
#define _SETCONFIG_H_
|
||||
|
||||
#define WITH_CONFIG
|
||||
|
||||
#ifdef WITH_CONFIG
|
||||
#include <config/config.h>
|
||||
@@ -49,13 +50,13 @@
|
||||
#define YAW_AIM_KI (0.01)
|
||||
#endif
|
||||
#ifndef PITCH_AIM_KD
|
||||
#define PITCH_AIM_KD (0.4)
|
||||
#define PITCH_AIM_KD (0)
|
||||
#endif
|
||||
#ifndef PITCH_AIM_KP
|
||||
#define PITCH_AIM_KP (0.75)
|
||||
#define PITCH_AIM_KP (0)
|
||||
#endif
|
||||
#ifndef PITCH_AIM_KI
|
||||
#define PITCH_AIM_KI (0.01)
|
||||
#define PITCH_AIM_KI (0)
|
||||
#endif
|
||||
|
||||
#ifndef RED_COMPENSATE_YAW
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
|
||||
#define FOCUS_PIXAL_8MM (1488)
|
||||
#define FOCUS_PIXAL_5MM (917)
|
||||
#define FOCUS_PIXAL FOCUS_PIXAL_5MM
|
||||
#define FOCUS_PIXAL FOCUS_PIXAL_8MM
|
||||
|
||||
#endif /* _CONSTANTS_H */
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <systime.h>
|
||||
#include <iostream>
|
||||
|
||||
/************** Define the control code *************/
|
||||
#define START_CTR "\033[0"
|
||||
|
||||
@@ -36,10 +36,10 @@ void uartReceive(Serial *pSerial) {
|
||||
pSerial->ReadData((uint8_t *) buffer, sizeof(mcu_data)+1);
|
||||
if (buffer[sizeof(mcu_data)] == '\n') {
|
||||
memcpy(&mcu_data, buffer, sizeof(mcu_data));
|
||||
// LOGM("Get, state:%c, mark:%d!", mcu_data.state, (int) mcu_data.mark);
|
||||
// LOGM("Get yaw: %f, pitch: %f!", mcu_data.curr_yaw, mcu_data.curr_pitch);
|
||||
// LOGM("Get delta x: %d, delta y: %d!", mcu_data.delta_x, mcu_data.delta_y);
|
||||
// static int t = time(nullptr);
|
||||
LOGM("Get, state:%c, mark:%d!", mcu_data.state, (int) mcu_data.mark);
|
||||
LOGM("Get yaw: %f, pitch: %f!", mcu_data.curr_yaw, mcu_data.curr_pitch);
|
||||
LOGM("Get delta x: %d, delta y: %d!", mcu_data.delta_x, mcu_data.delta_y);
|
||||
// static int t = time(nullptr);
|
||||
// static int cnt = 0;
|
||||
// if(time(nullptr) > t){
|
||||
// t = time(nullptr);
|
||||
@@ -77,8 +77,12 @@ bool checkReconnect(bool is_camera_connect) {
|
||||
if (!is_camera_connect) {
|
||||
int curr_gain = ((CameraWrapper* )video)->gain;
|
||||
int curr_exposure = ((CameraWrapper* )video)->exposure;
|
||||
int curr_mode = ((CameraWrapper* )video)->mode; // 获取原始模式
|
||||
|
||||
delete video;
|
||||
video = new CameraWrapper(curr_exposure, curr_gain, 0/*, "armor"*/);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 等待硬件释放
|
||||
video = new CameraWrapper(curr_exposure, curr_gain, curr_mode/*, "armor"*/);
|
||||
//video = new CameraWrapper(curr_exposure, curr_gain, 0/*, "armor"*/);
|
||||
is_camera_connect = video->init();
|
||||
}
|
||||
return is_camera_connect;
|
||||
@@ -103,14 +107,14 @@ void extract(cv::Mat &src) {//图像预处理,将视频切成640×480的大小
|
||||
if (src.empty()) return;
|
||||
float length = static_cast<float>(src.cols);
|
||||
float width = static_cast<float>(src.rows);
|
||||
if (length / width > 640.0 / 480.0) {
|
||||
length *= 480.0 / width;
|
||||
resize(src, src, cv::Size(length, 480));
|
||||
src = src(Rect((length - 640) / 2, 0, 640, 480));
|
||||
if (length / width > 1280.0 / 1024.0) {
|
||||
length *= 1024 / width;
|
||||
resize(src, src, cv::Size(length, 1024));
|
||||
src = src(Rect((length - 1280) / 2, 0, 1280, 1024));
|
||||
} else {
|
||||
width *= 640.0 / length;
|
||||
resize(src, src, cv::Size(640, width));
|
||||
src = src(Rect(0, (width - 480) / 2, 640, 480));
|
||||
width *= 1280.0 / length;
|
||||
resize(src, src, cv::Size(1280, width));
|
||||
src = src(Rect(0, (width - 1024) / 2, 1280, 1024));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ CameraWrapper::CameraWrapper(int exposure, int gain, int camera_mode, const std:
|
||||
mode(camera_mode),
|
||||
camera_cnts(2),
|
||||
camera_status(-1),
|
||||
iplImage(nullptr),
|
||||
rgb_buffer(nullptr),
|
||||
channel(3),
|
||||
gain(gain),
|
||||
@@ -27,9 +26,11 @@ CameraWrapper::CameraWrapper(int exposure, int gain, int camera_mode, const std:
|
||||
void cameraCallback(CameraHandle hCamera, BYTE *pFrameBuffer, tSdkFrameHead* pFrameHead,PVOID pContext){
|
||||
CameraWrapper *c = (CameraWrapper*)pContext;
|
||||
CameraImageProcess(hCamera, pFrameBuffer, c->rgb_buffer, pFrameHead);
|
||||
auto iplImage = cvCreateImageHeader(cvSize(pFrameHead->iWidth, pFrameHead->iHeight), IPL_DEPTH_8U, c->channel);
|
||||
cvSetData(iplImage, c->rgb_buffer, pFrameHead->iWidth * c->channel); //此处只是设置指针,无图像块数据拷贝,不需担心转换效率
|
||||
c->src_queue.push(cv::cvarrToMat(iplImage).clone());
|
||||
// 使用 cv::Mat 替代 IplImage
|
||||
cv::Mat img(pFrameHead->iHeight, pFrameHead->iWidth,
|
||||
c->channel == 3 ? CV_8UC3 : CV_8UC1,
|
||||
c->rgb_buffer, pFrameHead->iWidth * c->channel);
|
||||
c->src_queue.push(img.clone());
|
||||
}
|
||||
|
||||
bool CameraWrapper::init() {
|
||||
@@ -37,6 +38,7 @@ bool CameraWrapper::init() {
|
||||
int camera_enumerate_device_status = CameraEnumerateDevice(camera_enum_list, &camera_cnts);
|
||||
if (camera_enumerate_device_status != CAMERA_STATUS_SUCCESS) {
|
||||
LOGE("CameraEnumerateDevice fail with %d!", camera_enumerate_device_status);
|
||||
return false;
|
||||
}
|
||||
if (camera_cnts == 0) {
|
||||
LOGE("No camera device detected!");
|
||||
@@ -134,15 +136,9 @@ bool CameraWrapper::read(cv::Mat &src) {
|
||||
|
||||
bool CameraWrapper::readRaw(cv::Mat &src) {
|
||||
if (CameraGetImageBuffer(h_camera, &frame_info, &pby_buffer, 500) == CAMERA_STATUS_SUCCESS) {
|
||||
if (iplImage) {
|
||||
cvReleaseImageHeader(&iplImage);
|
||||
}
|
||||
|
||||
iplImage = cvCreateImageHeader(cvSize(frame_info.iWidth, frame_info.iHeight), IPL_DEPTH_8U, 1);
|
||||
|
||||
cvSetData(iplImage, pby_buffer, frame_info.iWidth); //此处只是设置指针,无图像块数据拷贝,不需担心转换效率
|
||||
|
||||
src = cv::cvarrToMat(iplImage).clone();
|
||||
// 使用 cv::Mat 替代 IplImage
|
||||
cv::Mat img(frame_info.iHeight, frame_info.iWidth, CV_8UC1, pby_buffer, frame_info.iWidth);
|
||||
src = img.clone();
|
||||
|
||||
//在成功调用CameraGetImageBuffer后,必须调用CameraReleaseImageBuffer来释放获得的buffer。
|
||||
//否则再次调用CameraGetImageBuffer时,程序将被挂起一直阻塞,直到其他线程中调用CameraReleaseImageBuffer来释放了buffer
|
||||
@@ -156,16 +152,13 @@ bool CameraWrapper::readRaw(cv::Mat &src) {
|
||||
}
|
||||
|
||||
bool CameraWrapper::readProcessed(cv::Mat &src) {
|
||||
// cerr << "Get-1" << endl;
|
||||
if (CameraGetImageBuffer(h_camera, &frame_info, &pby_buffer, 500) == CAMERA_STATUS_SUCCESS) {
|
||||
CameraImageProcess(h_camera, pby_buffer, rgb_buffer,
|
||||
&frame_info); // this function is super slow, better not to use it.
|
||||
if (iplImage) {
|
||||
cvReleaseImageHeader(&iplImage);
|
||||
}
|
||||
iplImage = cvCreateImageHeader(cvSize(frame_info.iWidth, frame_info.iHeight), IPL_DEPTH_8U, channel);
|
||||
cvSetData(iplImage, rgb_buffer, frame_info.iWidth * channel); //此处只是设置指针,无图像块数据拷贝,不需担心转换效率
|
||||
src = cv::cvarrToMat(iplImage).clone();
|
||||
// 使用 cv::Mat 替代 IplImage
|
||||
int mat_type = (channel == 3) ? CV_8UC3 : CV_8UC1;
|
||||
cv::Mat img(frame_info.iHeight, frame_info.iWidth, mat_type, rgb_buffer, frame_info.iWidth * channel);
|
||||
src = img.clone();
|
||||
//在成功调用CameraGetImageBuffer后,必须调用CameraReleaseImageBuffer来释放获得的buffer。
|
||||
//否则再次调用CameraGetImageBuffer时,程序将被挂起一直阻塞,直到其他线程中调用CameraReleaseImageBuffer来释放了buffer
|
||||
CameraReleaseImageBuffer(h_camera, pby_buffer);
|
||||
@@ -193,4 +186,4 @@ CameraWrapper::~CameraWrapper() {
|
||||
//注意,先反初始化后再free
|
||||
if (rgb_buffer != nullptr)
|
||||
free(rgb_buffer);
|
||||
}
|
||||
}
|
||||
@@ -6,19 +6,20 @@
|
||||
#include <log.h>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
bool show_armor_box = false;
|
||||
bool show_armor_box = true;
|
||||
bool show_armor_boxes = false;
|
||||
bool show_light_blobs = false;
|
||||
bool show_origin = false;
|
||||
bool run_with_camera = false;
|
||||
bool run_with_camera = true;
|
||||
bool save_video = false;
|
||||
bool wait_uart = false;
|
||||
bool save_labelled_boxes = false;
|
||||
bool show_process = false;
|
||||
bool show_energy = false;
|
||||
bool save_mark = false;
|
||||
bool show_info = false;
|
||||
bool show_info = true;
|
||||
bool run_by_frame = false;
|
||||
|
||||
// 使用map保存所有选项及其描述和操作,加快查找速度。
|
||||
|
||||
@@ -181,7 +181,7 @@ bool Serial::ReadData(unsigned char *buffer, unsigned int length) {
|
||||
using namespace std;
|
||||
|
||||
string get_uart_dev_name() {
|
||||
FILE *ls = popen("ls /dev/ttyUSB* --color=never", "r");
|
||||
FILE *ls = popen("ls /dev/ttyCH341USB* --color=never", "r");
|
||||
char name[20] = {0};
|
||||
fscanf(ls, "%s", name);
|
||||
return name;
|
||||
|
||||
3
tools/tty-permission.sh
Normal file
3
tools/tty-permission.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
sudo touch /etc/udev/rules.d/70-ttyusb.rules
|
||||
Reference in New Issue
Block a user