Skip to content

Commit 8d16c79

Browse files
committed
完成所有任务逻辑,添加代码注释
Signed-off-by: yuanlu <[email protected]>
1 parent 34392fe commit 8d16c79

File tree

1 file changed

+128
-35
lines changed

1 file changed

+128
-35
lines changed

src/main.cpp

+128-35
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
static_assert(__OS__ == __OS_Linux__);
1717

1818

19-
#define TIME 0
20-
#define DRAW 0
19+
#define TIME 0 // 是否启用时间调试
20+
#define DRAW 0 // 是否启用绘图调试
2121

2222
#if TIME
2323
#define REC_T(t) const auto ___time_rec___##t = cv::getTickCount()
@@ -40,23 +40,24 @@ std::string createWindow(const std::string &name) {
4040
#endif
4141

4242

43+
/// 处理器, 包含NUEDC 2023 E题所有视觉处理的功能
4344
class Handler {
44-
#define PAIR_MAT(name) cv::Mat c_##name;cv::cuda::GpuMat g_##name
45-
#define PM_MALLOC(name) memMapPool.malloc(c_##name, g_##name, src.size(), src.type())
45+
#define PAIR_MAT(name) cv::Mat c_##name;cv::cuda::GpuMat g_##name \
46+
/// 声明一对儿cpu/gpu mat
47+
#define PM_MALLOC(name) memMapPool.malloc(c_##name, g_##name, src.size(), src.type()) \
48+
/// 使用内存映射池为cpu/gpu mat构建映射关系
4649
public:
4750
cv::Point2d green, red;//激光位置
4851
std::vector<cv::Point> path;//路径
4952
private:
50-
int step = -1;
51-
cv::Point2d end;
52-
serial::Serial *serial = nullptr;
53+
serial::Serial *serial;
5354
ifr::pkg::Move pkg_move;
5455

55-
const double min_distance = std::pow(20.0, 2);
5656

57-
58-
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(10, 10));
59-
cv::Ptr<cv::cuda::Filter> filter = cv::cuda::createMorphologyFilter(cv::MORPH_OPEN, CV_8UC1, kernel);
57+
cv::Mat kernel1 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(10, 10));
58+
cv::Ptr<cv::cuda::Filter> filter1 = cv::cuda::createMorphologyFilter(cv::MORPH_OPEN, CV_8UC1, kernel1);
59+
cv::Mat kernel2 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
60+
cv::Ptr<cv::cuda::Filter> filter2 = cv::cuda::createMorphologyFilter(cv::MORPH_DILATE, CV_8UC1, kernel2);
6061
private:
6162
#if DRAW
6263

@@ -101,7 +102,7 @@ class Handler {
101102
REC_T(1);
102103
cv::threshold(c_gray, c_otsu, 30, 255, cv::THRESH_OTSU);
103104
REC_T(2);
104-
filter->apply(g_otsu, g_bin);
105+
filter1->apply(g_otsu, g_bin);
105106

106107

107108
REC_T(3);
@@ -205,19 +206,21 @@ class Handler {
205206
PAIR_MAT(hsv);
206207
PAIR_MAT(HSV[3]);
207208
PAIR_MAT(pointer);
209+
cv::cuda::GpuMat g_pointer_raw;
208210

209211
inline auto findPointer(rm_armor_finder::MemMapPool &memMapPool, const cv::Mat &src, const cv::cuda::GpuMat &gpu) {
210212
PM_MALLOC(hsv);
211213
#pragma unroll
212214
for (int i = 0; i < 3; i++)
213215
PM_MALLOC(HSV[i]);
214216
PM_MALLOC(pointer);
217+
if (g_pointer_raw.empty())g_pointer_raw.create(src.size(), CV_8UC1);
215218

216219
cv::cuda::cvtColor(gpu, g_hsv, cv::COLOR_BGR2HSV);
217220
cv::cuda::split(g_hsv, g_HSV);
218221

219-
ifr::cuda::findPointer(g_HSV[2], has_bin ? &g_bin : nullptr, g_pointer);
220-
222+
ifr::cuda::findPointer(g_HSV[2], has_bin ? &g_bin : nullptr, g_pointer_raw);
223+
filter2->apply(g_pointer_raw, g_pointer);
221224

222225
std::vector<std::vector<cv::Point>> contours;
223226
cv::findContours(c_pointer, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
@@ -232,7 +235,7 @@ class Handler {
232235
double size_green = 0, size_red = 0;
233236
for (const auto &contour: contours) {
234237
double area = cv::contourArea(contour);
235-
if (area > 300 || area < 5)continue;
238+
if (area > 500 || area < 5)continue;
236239
cv::Rect rect = cv::boundingRect(contour);
237240

238241
double aspectRatio = static_cast<double>(rect.width) / rect.height;
@@ -321,54 +324,137 @@ class Handler {
321324
PRINT_T(1, 5);
322325
}
323326

324-
cv::Point2d move_step() {
325-
if (red.x < 0 || red.y < 0)return {0, 0};
327+
private:
328+
int step = -1;///< red当前目标
329+
cv::Point2d end;///< red最终位置
330+
const double min_distance = 20.0; ///< red到达判定
331+
const double min_distance2 = std::pow(min_distance, 2); ///< red到达判定
332+
private:
333+
334+
/**
335+
* @brief 计算移动向量
336+
* @param go 目标点
337+
* @param now 当前点
338+
* @param mask 可用路径遮罩
339+
* @param[out] finish 是否完成
340+
*/
341+
inline auto calcMove(cv::Point2d go, const cv::Point2d &now, const cv::Mat &mask, bool &finish) const {
342+
static constexpr const auto r90 = 90 * CV_PI / 180.0;
343+
go -= now;
344+
if ((finish = (go.ddot(go) < min_distance2)))return go;
345+
go /= cv::norm(go);
346+
cv::Rect rect{0, 0, mask.cols, mask.rows};
347+
if (!now.inside(rect))return go * min_distance; //不太可能
348+
349+
const double angle = std::atan2(go.y - now.y, go.x - now.x) + r90;
350+
const auto in_path = mask.at<uchar>(int(now.y), int(now.x));
351+
const cv::Point2d detla{std::cos(angle), std::sin(angle)};
352+
353+
int dis_l = -1, dis_r = -1;
354+
for (int i = 0, max_val = mask.size().area(); i < max_val; i++) {//从now开始向垂直于前进方向两侧寻找第一个不同点
355+
if (dis_l < 0) {
356+
auto p1 = now - (i * detla);
357+
if (p1.inside(rect) && mask.at<uchar>(int(p1.y), int(p1.x)) != in_path) {
358+
dis_l = i;
359+
if (!in_path)break;//now 本身在黑条上
360+
}
361+
}
362+
if (dis_r < 0) {
363+
auto p2 = now + (i * detla);
364+
if (p2.inside(rect) && mask.at<uchar>(int(p2.y), int(p2.x)) != in_path) {
365+
dis_r = i;
366+
if (!in_path)break;//now 本身在黑条上
367+
}
368+
}
369+
if (dis_l >= 0 && dis_r >= 0)break;
370+
}
371+
372+
if (in_path) {//在路径中, 以小纠正得到结果
373+
if (dis_l >= 0 && dis_r >= 0) {
374+
auto fix = (dis_l < dis_r ? 1 : -1) * detla;
375+
go = go * 4 + fix;
376+
}
377+
} else {//不在路径中, 以大偏移量最快返回
378+
if (dis_l >= 0 || dis_r >= 0) {
379+
static constexpr const auto max_val = std::numeric_limits<int>::max();
380+
if (dis_l < 0)dis_l = max_val;
381+
if (dis_r < 0)dis_r = max_val;
382+
auto fix = (dis_l < dis_r ? -1 : 1) * detla;
383+
go = fix * 2 + go;
384+
}
385+
}
386+
go /= cv::norm(go) * min_distance;
387+
return go;
388+
}
389+
390+
/// red 帮助函数
391+
/// 尝试计算到目标点的距离, 并自动更新step
392+
cv::Point2d move_step(bool &finish) {
326393
if (step < 0) {
327394
end = red;
328395
step = 0;
329396
}
330-
while (step < path.size()) {
397+
if (step < path.size()) {
398+
#if 0
399+
cv::Point2d go = calcMove(path[step], red, c_bin, finish);
400+
#else
331401
cv::Point2d go = path[step];
332402
go -= red;
333-
if (go.ddot(go) < min_distance)
334-
step++;
335-
else
336-
return go;
403+
go = -go;
404+
finish = go.ddot(go) < min_distance2;
405+
#endif
406+
if (finish) step++;
407+
finish = false;//单步完成不是全部完成
408+
return go;
337409
}
338-
return end - red;
410+
auto go = end - red;
411+
finish = go.ddot(go) < min_distance;
412+
return go;
339413
}
340414

415+
/// green 帮助函数
341416
CV_NODISCARD_STD cv::Point2d follow() const {
342417
if (red.x < 0 || red.y < 0 || green.x < 0 || green.y < 0)return {};
343418
return green - red;
344419
}
345420

421+
public:
422+
/// @brief 执行一次绿色激光笔的代码逻辑: 计算移动+设置数据
346423
void do_green() {
347424
auto go = follow();
348425
pkg_move.set(go.x, go.y);
349426
IFR_LOG_STREAM("DO", go << ", red = " << red << ", green = " << green << ", path = " << path.size());
350-
serial->writeT(pkg_move);
351427
}
352428

429+
/// @brief 执行一次红色激光笔的代码逻辑: 计算移动+串口发送
353430
bool do_red() {
354431
cv::Point2d go;
355432
bool finish = false;
356433
if (red.x < 0 || red.y < 0) {
357434
} else {
358-
go = move_step();
359-
finish = go.ddot(go) < min_distance;
360-
if (finish)step = -1;
435+
go = move_step(finish);
436+
if (finish) {
437+
step = -1;
438+
go = {0, 0};
439+
}
361440
}
362441
pkg_move.set(go.x, go.y);
363-
serial->writeT(pkg_move);
364442
IFR_LOG_STREAM("DO",
365443
go << ", red = " << red << ", green = " << green << ", path = " << path.size() << ", finish = "
366444
<< (finish ? "true" : "false") << ", step = " << step);
367445
return finish;
368446
}
369447

448+
void sendMove() {
449+
serial->writeT(pkg_move);
450+
}
451+
452+
void resetMove() {
453+
pkg_move.set(0, 0);
454+
}
455+
370456
private:
371-
std::string read_buf;
457+
std::string read_buf;///串口缓冲
372458
public:
373459
/**
374460
* 尝试读取字符串, 并将maps中对应值设为true
@@ -392,12 +478,13 @@ class Handler {
392478
}
393479
}
394480
}
395-
if (read_buf.size() > 256)read_buf = "";
481+
if (read_buf.size() > 256)read_buf = "";//过长保护
396482
}
397483
}
398484
};
399485

400-
486+
/// @brief 执行完整代码逻辑
487+
/// @details 建立 相机、串口、处理器 之间的桥接
401488
void run() {
402489
ifr::Camera camera(2000, false, 100);
403490
camera.initCamera();
@@ -411,6 +498,8 @@ void run() {
411498
{"2_9kitey3yzpd", &is_red},
412499
{"3_yp4lmg19kbc", &is_stop},
413500
};
501+
502+
int64 lstTick = 0, now;
414503
while (true) {
415504
PGX_FRAME_BUFFER pFrameBuffer;
416505

@@ -424,19 +513,23 @@ void run() {
424513
handler.handler(camera.memMapPool, src, gpu_src, true);
425514

426515
handler.tryRead(keyword);
427-
if ((is_red && is_green) || is_stop)is_red = is_green = is_stop = false;
516+
if ((is_red && is_green) || is_stop) {
517+
handler.resetMove();
518+
is_red = is_green = is_stop = false;
519+
}
520+
is_red = true;
428521
if (is_red) {
429522
if (handler.do_red())is_red = false;
430523
}
431524
if (is_green) {
432525
handler.do_green();
433526
}
434-
// IFR_LOG_STREAM("Main", handler.path);
435527
}
436528
IFR_GX_CHECK(GXQBuf(camera.m_hDevice, pFrameBuffer));
437529

438-
SLEEP(SLEEP_TIME(10.0 / 1000));
439-
// cv::waitKey(10);
530+
while (double((now = cv::getTickCount()) - lstTick) / cv::getTickFrequency() * 1000 < 10.0);
531+
handler.sendMove();
532+
lstTick = now;
440533
}
441534
}
442535

0 commit comments

Comments
 (0)