Compare commits
10 Commits
41a31f1c18
...
15be04d1f7
| Author | SHA1 | Date | |
|---|---|---|---|
| 15be04d1f7 | |||
|
|
7770503779 | ||
|
|
5cf1a30ea0 | ||
|
|
7f6e2f4e6e | ||
|
|
0b1f5ff47f | ||
|
|
e1eb8b2590 | ||
|
|
b24542e97c | ||
|
|
de94ff2242 | ||
|
|
d5df7ce7da | ||
|
|
ef257b7df0 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,9 @@
|
|||||||
cmake-build-debug
|
cmake-build-debug
|
||||||
build
|
build
|
||||||
.idea
|
.idea
|
||||||
|
.xmake
|
||||||
|
.vscode/.cache
|
||||||
|
.vscode/compile_commands.json
|
||||||
Mark
|
Mark
|
||||||
armor_box_photo
|
armor_box_photo
|
||||||
tools/TrainCNN/.idea
|
tools/TrainCNN/.idea
|
||||||
|
|||||||
8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"clangd.arguments": [
|
||||||
|
"--compile-commands-dir=${workspaceFolder}/.vscode",
|
||||||
|
"--completion-style=detailed",
|
||||||
|
"--query-driver=/usr/bin/g++,/usr/bin/gcc,/usr/bin/c++",
|
||||||
|
"--header-insertion=never"
|
||||||
|
],
|
||||||
|
}
|
||||||
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或者想交流的朋友欢迎积极联系我们**
|
**如有BUG或者想交流的朋友欢迎积极联系我们**
|
||||||
|
|
||||||
|
**分享部分比赛时摄像头录制的视频:**
|
||||||
|
|
||||||
|
链接: https://pan.baidu.com/s/1LwxEpeYYblX3cSzb59MTVg 提取码: 84ju 复制这段内容后打开百度网盘手机App,操作更方便哦
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
运行效果:自瞄帧率120(摄像头最大帧率),识别距离根据环境不同大约8米左右(5mm焦距镜头)。
|
运行效果:自瞄帧率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 |
|
| 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环境下的运行支持,仅保证程序可以编译运行。对与部分辅助功能,如生成自启动脚本则不支持。**
|
**关于Windows环境下的运行支持,仅保证程序可以编译运行。对与部分辅助功能,如生成自启动脚本则不支持。**
|
||||||
|
|
||||||
**实际装载在步兵和哨兵上的运行环境为Ubuntu18.04。**
|
**实际装载在步兵和哨兵上的运行环境为Ubuntu18.04。**
|
||||||
@@ -60,6 +68,8 @@ sudo ./run
|
|||||||
|
|
||||||
```./run --help```可以查看所有命令行参数及其作用。所有调试选项都集成到了命令行参数中。
|
```./run --help```可以查看所有命令行参数及其作用。所有调试选项都集成到了命令行参数中。
|
||||||
|
|
||||||
|
**不使用任何参数直接运行将没有任何图像显示。**
|
||||||
|
|
||||||
需要调参的部分:主要需要根据车辆情况而调参的参数存放在others/include/config/setconfig.h中
|
需要调参的部分:主要需要根据车辆情况而调参的参数存放在others/include/config/setconfig.h中
|
||||||
|
|
||||||
### 3.工作条件
|
### 3.工作条件
|
||||||
@@ -118,7 +128,7 @@ sudo ./run
|
|||||||
### 1.自瞄装甲板识别方式
|
### 1.自瞄装甲板识别方式
|
||||||
|
|
||||||
首先对图像进行通道拆分以及二值化操作,再进行开闭运算,通过边缘提取和条件限制得出可能为灯条的部分。再对所有可能的灯条进行两两匹配,根据形状大小特性进行筛选,得出可能为装甲板的候选区。然后把所有候选区交给分类器判断,得出真实的装甲板及其数字id。最后根据优先级选取最终击打目标以及后续处理。
|
首先对图像进行通道拆分以及二值化操作,再进行开闭运算,通过边缘提取和条件限制得出可能为灯条的部分。再对所有可能的灯条进行两两匹配,根据形状大小特性进行筛选,得出可能为装甲板的候选区。然后把所有候选区交给分类器判断,得出真实的装甲板及其数字id。最后根据优先级选取最终击打目标以及后续处理。
|
||||||
|

|
||||||
### 2.能量机关识别方式
|
### 2.能量机关识别方式
|
||||||
|
|
||||||
首先对图像进行二值化操作,然后进行一定腐蚀和膨胀,通过边缘提取和条件限制得出待击打叶片(锤子形)。在待击打叶片范围内进一步用类似方法寻找目标装甲板和流动条,在二者连线上寻找中心的“R”。根据目标装甲板坐标和中心坐标计算极坐标系下的目标角度,进而预测待击打点的坐标(小符为装甲板本身,大符需要旋转)。最后将待击打点坐标和图像中心的差值转换为yaw和pitch轴角度,增加一环PID后发送给云台主控板。
|
首先对图像进行二值化操作,然后进行一定腐蚀和膨胀,通过边缘提取和条件限制得出待击打叶片(锤子形)。在待击打叶片范围内进一步用类似方法寻找目标装甲板和流动条,在二者连线上寻找中心的“R”。根据目标装甲板坐标和中心坐标计算极坐标系下的目标角度,进而预测待击打点的坐标(小符为装甲板本身,大符需要旋转)。最后将待击打点坐标和图像中心的差值转换为yaw和pitch轴角度,增加一环PID后发送给云台主控板。
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <systime.h>
|
#include <systime.h>
|
||||||
#include <constants.h>
|
#include <constants.h>
|
||||||
#include <opencv2/core.hpp>
|
#include <opencv2/core.hpp>
|
||||||
#include <opencv2/tracking.hpp>
|
#include <opencv2/tracking/tracking.hpp>
|
||||||
#include <serial.h>
|
#include <serial.h>
|
||||||
#include <armor_finder/classifier/classifier.h>
|
#include <armor_finder/classifier/classifier.h>
|
||||||
#include <additions.h>
|
#include <additions.h>
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ void ArmorFinder::run(cv::Mat &src) {
|
|||||||
if ((target_box.rect & cv::Rect2d(0, 0, 640, 480)) == target_box.rect) { // 判断装甲板区域是否脱离图像区域
|
if ((target_box.rect & cv::Rect2d(0, 0, 640, 480)) == target_box.rect) { // 判断装甲板区域是否脱离图像区域
|
||||||
if (!classifier) { /* 如果分类器不可用 */
|
if (!classifier) { /* 如果分类器不可用 */
|
||||||
cv::Mat roi = src(target_box.rect).clone(), roi_gray; /* 就使用装甲区域亮点数判断是否跟丢 */
|
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);
|
cv::threshold(roi_gray, roi_gray, 180, 255, cv::THRESH_BINARY);
|
||||||
contour_area = cv::countNonZero(roi_gray);
|
contour_area = cv::countNonZero(roi_gray);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ bool ArmorFinder::findArmorBox(const cv::Mat &src, ArmorBox &box) {
|
|||||||
for (auto &one_box : armor_boxes) {
|
for (auto &one_box : armor_boxes) {
|
||||||
if (one_box.id != 0) {
|
if (one_box.id != 0) {
|
||||||
box = one_box;
|
box = one_box;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (save_labelled_boxes) {
|
if (save_labelled_boxes) {
|
||||||
|
|||||||
@@ -83,11 +83,11 @@ bool ArmorFinder::findLightBlobs(const cv::Mat &src, LightBlobs &light_blobs) {
|
|||||||
}else{
|
}else{
|
||||||
light_threshold = 200;
|
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;
|
if (src_bin_light.empty()) return false;
|
||||||
imagePreProcess(src_bin_light); // 开闭运算
|
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;
|
if (src_bin_dim.empty()) return false;
|
||||||
imagePreProcess(src_bin_dim); // 开闭运算
|
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;
|
std::vector<std::vector<cv::Point>> light_contours_light, light_contours_dim;
|
||||||
LightBlobs light_blobs_light, light_blobs_dim;
|
LightBlobs light_blobs_light, light_blobs_dim;
|
||||||
std::vector<cv::Vec4i> hierarchy_light, hierarchy_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_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_dim, light_contours_dim, hierarchy_dim, cv::RETR_CCOMP, cv::CHAIN_APPROX_NONE);
|
||||||
for (int i = 0; i < light_contours_light.size(); i++) {
|
for (int i = 0; i < light_contours_light.size(); i++) {
|
||||||
if (hierarchy_light[i][2] == -1) {
|
if (hierarchy_light[i][2] == -1) {
|
||||||
cv::RotatedRect rect = cv::minAreaRect(light_contours_light[i]);
|
cv::RotatedRect rect = cv::minAreaRect(light_contours_light[i]);
|
||||||
|
|||||||
@@ -8,13 +8,13 @@
|
|||||||
#include <show_images/show_images.h>
|
#include <show_images/show_images.h>
|
||||||
|
|
||||||
bool ArmorFinder::stateTrackingTarget(cv::Mat &src) {
|
bool ArmorFinder::stateTrackingTarget(cv::Mat &src) {
|
||||||
auto pos = target_box.rect;
|
cv::Rect pos(target_box.rect);
|
||||||
if(!tracker->update(src, pos)){ // 使用KCFTracker进行追踪
|
if(!tracker->update(src, pos)){ // 使用KCFTracker进行追踪
|
||||||
target_box = ArmorBox();
|
target_box = ArmorBox();
|
||||||
LOGW("Track fail!");
|
LOGW("Track fail!");
|
||||||
return false;
|
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();
|
target_box = ArmorBox();
|
||||||
LOGW("Track out range!");
|
LOGW("Track out range!");
|
||||||
return false;
|
return false;
|
||||||
@@ -52,7 +52,7 @@ bool ArmorFinder::stateTrackingTarget(cv::Mat &src) {
|
|||||||
}
|
}
|
||||||
}else{ // 分类器不可用,使用常规方法判断
|
}else{ // 分类器不可用,使用常规方法判断
|
||||||
cv::Mat roi_gray;
|
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);
|
cv::threshold(roi_gray, roi_gray, 180, 255, cv::THRESH_BINARY);
|
||||||
contour_area = cv::countNonZero(roi_gray);
|
contour_area = cv::countNonZero(roi_gray);
|
||||||
if(abs(cv::countNonZero(roi_gray) - contour_area) > contour_area * 0.3){
|
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;
|
static Mat src_bin;
|
||||||
src_bin = src.clone();
|
src_bin = src.clone();
|
||||||
if (src.type() == CV_8UC3) {
|
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;
|
std::vector<vector<Point> > fan_contours;
|
||||||
FanStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找
|
FanStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找
|
||||||
if (show_process)imshow("fan struct", 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) {
|
for (auto &fan_contour : fan_contours) {
|
||||||
if (!isValidFanContour(src_bin, fan_contour)) {
|
if (!isValidFanContour(src_bin, fan_contour)) {
|
||||||
@@ -54,16 +54,16 @@ int Energy::findArmors(const cv::Mat &src) {
|
|||||||
static Mat src_bin;
|
static Mat src_bin;
|
||||||
src_bin = src.clone();
|
src_bin = src.clone();
|
||||||
if (src.type() == CV_8UC3) {
|
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;
|
||||||
std::vector<vector<Point> > armor_contours_external;//用总轮廓减去外轮廓,只保留内轮廓,除去流动条的影响。
|
std::vector<vector<Point> > armor_contours_external;//用总轮廓减去外轮廓,只保留内轮廓,除去流动条的影响。
|
||||||
|
|
||||||
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);
|
||||||
if (show_process)imshow("armor struct", src_bin);
|
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++)//去除外轮廓
|
for (int i = 0; i < armor_contours_external.size(); i++)//去除外轮廓
|
||||||
{
|
{
|
||||||
unsigned long external_contour_size = armor_contours_external[i].size();
|
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;
|
static Mat src_bin;
|
||||||
src_bin = src.clone();
|
src_bin = src.clone();
|
||||||
if (src.type() == CV_8UC3) {
|
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;
|
std::vector<vector<Point> > center_R_contours;
|
||||||
CenterRStruct(src_bin);
|
CenterRStruct(src_bin);
|
||||||
if (show_process)imshow("R struct", 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) {
|
for (auto ¢er_R_contour : center_R_contours) {
|
||||||
if (!isValidCenterRContour(center_R_contour)) {
|
if (!isValidCenterRContour(center_R_contour)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -139,13 +139,13 @@ bool Energy::findFlowStripFan(const cv::Mat &src) {
|
|||||||
src_bin = src.clone();
|
src_bin = src.clone();
|
||||||
src_copy = src.clone();
|
src_copy = src.clone();
|
||||||
if (src.type() == CV_8UC3) {
|
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;
|
std::vector<vector<Point> > flow_strip_fan_contours;
|
||||||
FlowStripFanStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找
|
FlowStripFanStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找
|
||||||
if (show_process)imshow("flow strip fan struct", 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;
|
std::vector<cv::RotatedRect> candidate_flow_strip_fans;
|
||||||
|
|
||||||
for (auto &flow_strip_fan_contour : flow_strip_fan_contours) {
|
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) // 黑白图像
|
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;
|
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);//图像膨胀,防止图像断开并更方便寻找
|
FlowStripStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找
|
||||||
if (show_process)imshow("flow strip struct", src_bin);
|
if (show_process)imshow("flow strip struct", src_bin);
|
||||||
|
|
||||||
std::vector<vector<Point> > flow_strip_contours;
|
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 candidate_flow_strip_fan: flow_strip_fans) {
|
||||||
for (auto &flow_strip_contour : flow_strip_contours) {
|
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) // 黑白图像
|
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;
|
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);//图像膨胀,防止图像断开并更方便寻找
|
FlowStripStruct(src_bin);//图像膨胀,防止图像断开并更方便寻找
|
||||||
if (show_process)imshow("weak struct", src_bin);
|
if (show_process)imshow("weak struct", src_bin);
|
||||||
|
|
||||||
std::vector<vector<Point> > flow_strip_contours;
|
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) {
|
for (auto &flow_strip_contour : flow_strip_contours) {
|
||||||
if (!isValidFlowStripContour(flow_strip_contour)) {
|
if (!isValidFlowStripContour(flow_strip_contour)) {
|
||||||
@@ -336,5 +336,3 @@ bool Energy::findCenterROI(const cv::Mat &src) {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#define _CAMERA_WRAPPER_H_
|
#define _CAMERA_WRAPPER_H_
|
||||||
|
|
||||||
#include <additions.h>
|
#include <additions.h>
|
||||||
#include <opencv2/core/core.hpp>
|
#include <opencv2/core.hpp>
|
||||||
#include <camera/wrapper_head.h>
|
#include <camera/wrapper_head.h>
|
||||||
|
|
||||||
#ifdef Windows
|
#ifdef Windows
|
||||||
@@ -33,7 +33,7 @@ private:
|
|||||||
tSdkCameraCapbility tCapability;
|
tSdkCameraCapbility tCapability;
|
||||||
tSdkFrameHead frame_info;
|
tSdkFrameHead frame_info;
|
||||||
BYTE *pby_buffer;
|
BYTE *pby_buffer;
|
||||||
IplImage* iplImage;
|
cv::Mat image_header;
|
||||||
int channel;
|
int channel;
|
||||||
|
|
||||||
RoundQueue<cv::Mat, 2> src_queue;
|
RoundQueue<cv::Mat, 2> src_queue;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <systime.h>
|
#include <systime.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
/************** Define the control code *************/
|
/************** Define the control code *************/
|
||||||
#define START_CTR "\033[0"
|
#define START_CTR "\033[0"
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ CameraWrapper::CameraWrapper(int exposure, int gain, int camera_mode, const std:
|
|||||||
mode(camera_mode),
|
mode(camera_mode),
|
||||||
camera_cnts(2),
|
camera_cnts(2),
|
||||||
camera_status(-1),
|
camera_status(-1),
|
||||||
iplImage(nullptr),
|
|
||||||
rgb_buffer(nullptr),
|
rgb_buffer(nullptr),
|
||||||
channel(3),
|
channel(3),
|
||||||
gain(gain),
|
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){
|
void cameraCallback(CameraHandle hCamera, BYTE *pFrameBuffer, tSdkFrameHead* pFrameHead,PVOID pContext){
|
||||||
CameraWrapper *c = (CameraWrapper*)pContext;
|
CameraWrapper *c = (CameraWrapper*)pContext;
|
||||||
CameraImageProcess(hCamera, pFrameBuffer, c->rgb_buffer, pFrameHead);
|
CameraImageProcess(hCamera, pFrameBuffer, c->rgb_buffer, pFrameHead);
|
||||||
auto iplImage = cvCreateImageHeader(cvSize(pFrameHead->iWidth, pFrameHead->iHeight), IPL_DEPTH_8U, c->channel);
|
// 使用 cv::Mat 替代 IplImage
|
||||||
cvSetData(iplImage, c->rgb_buffer, pFrameHead->iWidth * c->channel); //此处只是设置指针,无图像块数据拷贝,不需担心转换效率
|
cv::Mat img(pFrameHead->iHeight, pFrameHead->iWidth,
|
||||||
c->src_queue.push(cv::cvarrToMat(iplImage).clone());
|
c->channel == 3 ? CV_8UC3 : CV_8UC1,
|
||||||
|
c->rgb_buffer, pFrameHead->iWidth * c->channel);
|
||||||
|
c->src_queue.push(img.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CameraWrapper::init() {
|
bool CameraWrapper::init() {
|
||||||
@@ -134,15 +135,9 @@ bool CameraWrapper::read(cv::Mat &src) {
|
|||||||
|
|
||||||
bool CameraWrapper::readRaw(cv::Mat &src) {
|
bool CameraWrapper::readRaw(cv::Mat &src) {
|
||||||
if (CameraGetImageBuffer(h_camera, &frame_info, &pby_buffer, 500) == CAMERA_STATUS_SUCCESS) {
|
if (CameraGetImageBuffer(h_camera, &frame_info, &pby_buffer, 500) == CAMERA_STATUS_SUCCESS) {
|
||||||
if (iplImage) {
|
// 使用 cv::Mat 替代 IplImage
|
||||||
cvReleaseImageHeader(&iplImage);
|
cv::Mat img(frame_info.iHeight, frame_info.iWidth, CV_8UC1, pby_buffer, frame_info.iWidth);
|
||||||
}
|
src = img.clone();
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
//在成功调用CameraGetImageBuffer后,必须调用CameraReleaseImageBuffer来释放获得的buffer。
|
//在成功调用CameraGetImageBuffer后,必须调用CameraReleaseImageBuffer来释放获得的buffer。
|
||||||
//否则再次调用CameraGetImageBuffer时,程序将被挂起一直阻塞,直到其他线程中调用CameraReleaseImageBuffer来释放了buffer
|
//否则再次调用CameraGetImageBuffer时,程序将被挂起一直阻塞,直到其他线程中调用CameraReleaseImageBuffer来释放了buffer
|
||||||
@@ -156,16 +151,13 @@ bool CameraWrapper::readRaw(cv::Mat &src) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CameraWrapper::readProcessed(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) {
|
if (CameraGetImageBuffer(h_camera, &frame_info, &pby_buffer, 500) == CAMERA_STATUS_SUCCESS) {
|
||||||
CameraImageProcess(h_camera, pby_buffer, rgb_buffer,
|
CameraImageProcess(h_camera, pby_buffer, rgb_buffer,
|
||||||
&frame_info); // this function is super slow, better not to use it.
|
&frame_info); // this function is super slow, better not to use it.
|
||||||
if (iplImage) {
|
// 使用 cv::Mat 替代 IplImage
|
||||||
cvReleaseImageHeader(&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);
|
||||||
iplImage = cvCreateImageHeader(cvSize(frame_info.iWidth, frame_info.iHeight), IPL_DEPTH_8U, channel);
|
src = img.clone();
|
||||||
cvSetData(iplImage, rgb_buffer, frame_info.iWidth * channel); //此处只是设置指针,无图像块数据拷贝,不需担心转换效率
|
|
||||||
src = cv::cvarrToMat(iplImage).clone();
|
|
||||||
//在成功调用CameraGetImageBuffer后,必须调用CameraReleaseImageBuffer来释放获得的buffer。
|
//在成功调用CameraGetImageBuffer后,必须调用CameraReleaseImageBuffer来释放获得的buffer。
|
||||||
//否则再次调用CameraGetImageBuffer时,程序将被挂起一直阻塞,直到其他线程中调用CameraReleaseImageBuffer来释放了buffer
|
//否则再次调用CameraGetImageBuffer时,程序将被挂起一直阻塞,直到其他线程中调用CameraReleaseImageBuffer来释放了buffer
|
||||||
CameraReleaseImageBuffer(h_camera, pby_buffer);
|
CameraReleaseImageBuffer(h_camera, pby_buffer);
|
||||||
|
|||||||
@@ -6,12 +6,13 @@
|
|||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
bool show_armor_box = false;
|
bool show_armor_box = true;
|
||||||
bool show_armor_boxes = false;
|
bool show_armor_boxes = false;
|
||||||
bool show_light_blobs = false;
|
bool show_light_blobs = false;
|
||||||
bool show_origin = false;
|
bool show_origin = false;
|
||||||
bool run_with_camera = false;
|
bool run_with_camera = true;
|
||||||
bool save_video = false;
|
bool save_video = false;
|
||||||
bool wait_uart = false;
|
bool wait_uart = false;
|
||||||
bool save_labelled_boxes = false;
|
bool save_labelled_boxes = false;
|
||||||
|
|||||||
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
|
||||||
122
xmake.lua
Normal file
122
xmake.lua
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
-- 设置项目信息
|
||||||
|
set_project("SJTU-RM-CV")
|
||||||
|
set_version("1.0.0")
|
||||||
|
set_languages("c++17")
|
||||||
|
|
||||||
|
-- 设置构建模式
|
||||||
|
set_rules("mode.release")
|
||||||
|
set_optimize("fastest")
|
||||||
|
|
||||||
|
--导出构建指令
|
||||||
|
add_rules("plugin.compile_commands.autoupdate", {outputdir = ".vscode"})
|
||||||
|
|
||||||
|
-- 定义宏
|
||||||
|
add_defines('PATH=\"$(projectdir)\"')
|
||||||
|
add_defines("Linux")
|
||||||
|
|
||||||
|
-- 检查是否存在 config.h
|
||||||
|
if os.isfile("others/include/config/config.h") or os.isfile("others/include/config.h") then
|
||||||
|
add_defines("WITH_CONFIG")
|
||||||
|
print("Found config.h")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 添加依赖
|
||||||
|
add_requires("eigen", {system = false})
|
||||||
|
add_requires("pthread")
|
||||||
|
|
||||||
|
--- OpenCV 4.6.0 配置(启用 ffmpeg 和 contrib)
|
||||||
|
add_requires("opencv", {
|
||||||
|
system = false,
|
||||||
|
configs = {
|
||||||
|
ffmpeg = false,
|
||||||
|
eigen = true,
|
||||||
|
png = true,
|
||||||
|
jpeg = true,
|
||||||
|
webp = false,
|
||||||
|
tiff = false,
|
||||||
|
quirc = false,
|
||||||
|
opengl = false,
|
||||||
|
protobuf = false,
|
||||||
|
bundled = true,
|
||||||
|
gtk = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
-- 目标配置
|
||||||
|
target("run")
|
||||||
|
set_kind("binary")
|
||||||
|
|
||||||
|
-- 添加源文件
|
||||||
|
add_files("main.cpp")
|
||||||
|
add_files("others/src/*.cpp")
|
||||||
|
add_files("others/src/camera/*.cpp")
|
||||||
|
add_files("energy/src/energy/*.cpp")
|
||||||
|
add_files("energy/src/energy/*/*.cpp")
|
||||||
|
add_files("armor/src/armor_finder/*.cpp")
|
||||||
|
add_files("armor/src/armor_finder/*/*.cpp")
|
||||||
|
add_files("armor/src/show_images/*.cpp")
|
||||||
|
|
||||||
|
-- 添加头文件搜索路径
|
||||||
|
add_includedirs("others/include")
|
||||||
|
add_includedirs("others/include/camera")
|
||||||
|
add_includedirs("others/include/config")
|
||||||
|
add_includedirs("energy/include")
|
||||||
|
add_includedirs("energy/include/energy")
|
||||||
|
add_includedirs("armor/include")
|
||||||
|
add_includedirs("armor/include/armor_finder")
|
||||||
|
add_includedirs("armor/include/armor_finder/classifier")
|
||||||
|
add_includedirs("armor/include/show_images")
|
||||||
|
|
||||||
|
-- 添加依赖包
|
||||||
|
add_packages("pthread", "eigen", "opencv")
|
||||||
|
|
||||||
|
-- 添加链接目录
|
||||||
|
add_linkdirs("others")
|
||||||
|
|
||||||
|
-- 根据平台链接相机 SDK
|
||||||
|
if is_plat("linux") then
|
||||||
|
add_links("MVSDK")
|
||||||
|
print("current platform: Linux")
|
||||||
|
elseif is_plat("windows") then
|
||||||
|
add_links("MVCAMSDK_X64")
|
||||||
|
print("current platform: Windows")
|
||||||
|
elseif is_plat("macosx") then
|
||||||
|
add_links("mvsdk")
|
||||||
|
print("current platform: Mac")
|
||||||
|
else
|
||||||
|
print("Unsupported platform")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 设置目标目录
|
||||||
|
set_targetdir("$(builddir)")
|
||||||
|
|
||||||
|
-- 添加编译选项
|
||||||
|
add_cxxflags("-O3")
|
||||||
|
|
||||||
|
-- 自定义任务:create-startup
|
||||||
|
task("create-startup")
|
||||||
|
set_category("action")
|
||||||
|
on_run(function ()
|
||||||
|
os.exec("$(projectdir)/tools/create-startup.sh $(projectdir) $(builddir)")
|
||||||
|
end)
|
||||||
|
set_menu {
|
||||||
|
usage = "xmake create-startup",
|
||||||
|
description = "Create startup script",
|
||||||
|
options = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- 自定义任务:train-cnn
|
||||||
|
task("train-cnn")
|
||||||
|
set_category("action")
|
||||||
|
on_run(function ()
|
||||||
|
if os.host() == "linux" then
|
||||||
|
os.exec("gnome-terminal -- bash -c \"$(projectdir)/tools/TrainCNN/backward.py\"")
|
||||||
|
else
|
||||||
|
print("train-cnn only supported on Linux with gnome-terminal")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
set_menu {
|
||||||
|
usage = "xmake train-cnn",
|
||||||
|
description = "Train CNN model",
|
||||||
|
options = {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user