333333333

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include <serial/serial.h>  // 需要安装serial库

// 定义固定的头和尾
const char HEADER = 0x0a;  
const char FOOTER = 0x0b;  

// 定义初始的红色HSV范围
int h_min1 = 0, s_min1 = 120, v_min1 = 70;
int h_max1 = 10, s_max1 = 255, v_max1 = 255;
int h_min2 = 160, s_min2 = 120, v_min2 = 70;
int h_max2 = 180, s_max2 = 255, v_max2 = 255;

// 滑动条回调函数,这里可以为空,因为我们在主循环中直接读取滑动条的值
void on_trackbar(int, void*) {}

int main() {
    // 打开串口
    serial::Serial my_serial("/dev/ttyUSB0", 115200, serial::Timeout::simpleTimeout(1000));
    if (!my_serial.isOpen()) {
        std::cerr << "无法打开串口!" << std::endl;
        return -1;
    }

    // 打开摄像头
    cv::VideoCapture cap(0);
    if (!cap.isOpened()) {
        std::cerr << "无法打开摄像头!" << std::endl;
        return -1;
    }

    cv::namedWindow("检测结果", cv::WINDOW_AUTOSIZE);
    cv::namedWindow("HSV设置", cv::WINDOW_AUTOSIZE);

    // 创建滑动条
    cv::createTrackbar("H Min1", "HSV设置", &h_min1, 180, on_trackbar);
    cv::createTrackbar("S Min1", "HSV设置", &s_min1, 255, on_trackbar);
    cv::createTrackbar("V Min1", "HSV设置", &v_min1, 255, on_trackbar);
    cv::createTrackbar("H Max1", "HSV设置", &h_max1, 180, on_trackbar);
    cv::createTrackbar("S Max1", "HSV设置", &s_max1, 255, on_trackbar);
    cv::createTrackbar("V Max1", "HSV设置", &v_max1, 255, on_trackbar);

    cv::createTrackbar("H Min2", "HSV设置", &h_min2, 180, on_trackbar);
    cv::createTrackbar("S Min2", "HSV设置", &s_min2, 255, on_trackbar);
    cv::createTrackbar("V Min2", "HSV设置", &v_min2, 255, on_trackbar);
    cv::createTrackbar("H Max2", "HSV设置", &h_max2, 180, on_trackbar);
    cv::createTrackbar("S Max2", "HSV设置", &s_max2, 255, on_trackbar);
    cv::createTrackbar("V Max2", "HSV设置", &v_max2, 255, on_trackbar);

    while (true)
    {
        cv::Mat frame, hsv, red_mask1, red_mask2, red_mask;

        // 读取帧
        cap >> frame;
        if (frame.empty())
            break;

        // 转换为HSV色彩空间
        cv::cvtColor(frame, hsv, cv::COLOR_BGR2HSV);

        // 创建红色掩模(两个范围,因为红色在HSV色环的两端)
        cv::Scalar RED_LOWER1(h_min1, s_min1, v_min1);
        cv::Scalar RED_UPPER1(h_max1, s_max1, v_max1);
        cv::Scalar RED_LOWER2(h_min2, s_min2, v_min2);
        cv::Scalar RED_UPPER2(h_max2, s_max2, v_max2);

        cv::inRange(hsv, RED_LOWER1, RED_UPPER1, red_mask1);
        cv::inRange(hsv, RED_LOWER2, RED_UPPER2, red_mask2);
        cv::bitwise_or(red_mask1, red_mask2, red_mask);

        // 形态学操作(去除噪声)
        cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5));
        cv::morphologyEx(red_mask, red_mask, cv::MORPH_OPEN, kernel);
        cv::morphologyEx(red_mask, red_mask, cv::MORPH_CLOSE, kernel);

        // 查找轮廓
        std::vector<std::vector<cv::Point>> contours;
        cv::findContours(red_mask.clone(), contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

        // 检测圆形
        for (size_t i = 0; i < contours.size(); i++)
        {
            double area = cv::contourArea(contours[i]);

            // 过滤小区域
            if (area < 300)
                continue;

            // 计算最小外接圆
            cv::Point2f center;
            float radius;
            cv::minEnclosingCircle(contours[i], center, radius);

            // 计算圆形度
            double perimeter = cv::arcLength(contours[i], true);
            double circularity = (4 * CV_PI * area) / (perimeter * perimeter);

            // 如果是圆形(圆形度接近1)
            if (circularity > 0.7) {
                // 绘制圆形和中心点
                cv::circle(frame, center, static_cast<int>(radius), cv::Scalar(0, 255, 0), 2);
                cv::circle(frame, center, 3, cv::Scalar(0, 0, 255), -1);

                // 显示半径
                std::string radiusText = "R: " + std::to_string(static_cast<int>(radius));
                cv::putText(frame, radiusText, cv::Point(center.x, center.y - 20),
                            cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(255, 255, 255), 1);

                // 显示中心点坐标
                std::string centerText = "(" + std::to_string(static_cast<int>(center.x)) + ", " + std::to_string(static_cast<int>(center.y)) + ")";
                cv::putText(frame, centerText, cv::Point(center.x, center.y + 20),
                            cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(255, 255, 255), 1);

                // 发送头
                my_serial.write(&HEADER, 1);

                // 发送坐标到串口
                float x = center.x;
                float y = center.y;
                my_serial.write((char*)&x, sizeof(float));
                my_serial.write((char*)&y, sizeof(float));

                // 发送尾
                my_serial.write(&FOOTER, 1);
            }
        }

        // 显示结果
        cv::imshow("检测结果", frame);
        cv::imshow("红色掩模", red_mask);

        // 按'q'退出
        if (cv::waitKey(30) == 'q') break;
    }

    cap.release();
    cv::destroyAllWindows();
    my_serial.close();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值