#include #include // 包含SpireCV SDK头文件 #include using namespace std; // 定义窗口名称 static const std::string RGB_WINDOW = "Image window"; // 框选到的矩形 cv::Rect rect_sel; // 框选起始点 cv::Point pt_origin; // 是否得到一个新的框选区域 bool b_renew_ROI = false; // 是否开始跟踪 bool b_begin_TRACK = false; // 实现框选逻辑的回调函数 void onMouse(int event, int x, int y, int, void *); struct node { double x, y; }; node p1, p2, p3, p4; node p; double getCross(node p1, node p2, node p) { return (p2.x - p1.x) * (p.y - p1.y) - (p.x - p1.x) * (p2.y - p1.y); } bool b_clicked = false; bool detect_tracking = true; // 定义吊舱 sv::Gimbal *gimbal; // 吊舱状态获取回调函数 void GimableCallback(double &frame_ang_r, double &frame_ang_p, double &frame_ang_y, double &imu_ang_r, double &imu_ang_p, double &imu_ang_y, double &fov_x, double &fov_y); // 使用KP控制器实现吊舱追踪 void gimbalTrack(double xOffset, double yOffset) { gimbal->setAngleRateEuler(0, yOffset * 150.0f, xOffset * 150.0f); } // 停止吊舱追踪 void gimbalNoTrack(void) { gimbal->setAngleRateEuler(0, 0, 0); } int main(int argc, char *argv[]) { // 实例化吊舱 gimbal = new sv::Gimbal(sv::GimbalType::G1, sv::GimbalLink::SERIAL); // 使用 /dev/ttyUSB0 作为控制串口 gimbal->setSerialPort("/dev/ttyUSB0"); // 以GimableCallback作为状态回调函数启用吊舱控制 gimbal->open(GimableCallback); // 定义相机 sv::Camera cap; // 设置相机流媒体地址为 192.168.2.64 cap.setIp("192.168.2.64"); // 设置获取画面分辨率为720P cap.setWH(1280, 720); // 设置视频帧率为30帧 cap.setFps(30); // 开启相机 cap.open(sv::CameraType::G1); // 定义一个新的窗口,可在上面进行框选操作 cv::namedWindow(RGB_WINDOW); // 设置窗口操作回调函数,该函数实现整个框选逻辑 cv::setMouseCallback(RGB_WINDOW, onMouse, 0); // 实例化 框选目标跟踪类 sv::SingleObjectTracker sot; // 手动导入相机参数,如果使用Amov的G1等吊舱或相机,则可以忽略该步骤,将自动下载相机参数文件 sot.loadCameraParams(sv::get_home() + "/SpireCV/calib_webcam_640x480.yaml"); sv::CommonObjectDetector cod; cod.loadCameraParams(sv::get_home() + "/SpireCV/calib_webcam_640x480.yaml"); // 实例化OpenCV的Mat类,用于内存单帧图像 cv::Mat img; int frame_id = 0; while (1) { if (detect_tracking == true) { // 实例化SpireCV的 单帧检测结果 接口类 TargetsInFrame sv::TargetsInFrame tgts(frame_id++); // 读取一帧图像到img cap.read(img); cv::resize(img, img, cv::Size(cod.image_width, cod.image_height)); // 执行通用目标检测 cod.detect(img, tgts); gimbalNoTrack(); // 可视化检测结果,叠加到img上 sv::drawTargetsInFrame(img, tgts); // 控制台打印通用目标检测结果 printf("Frame-[%d]\n", frame_id); // 打印当前检测的FPS printf(" FPS = %.2f\n", tgts.fps); // 打印当前相机的视场角(degree) printf(" FOV (fx, fy) = (%.2f, %.2f)\n", tgts.fov_x, tgts.fov_y); for (int i = 0; i < tgts.targets.size(); i++) { printf("Frame-[%d], Object-[%d]\n", frame_id, i); // 打印每个目标的中心位置,cx,cy的值域为[0, 1] printf(" Object Center (cx, cy) = (%.3f, %.3f)\n", tgts.targets[i].cx, tgts.targets[i].cy); // 打印每个目标的外接矩形框的宽度、高度,w,h的值域为(0, 1] printf(" Object Size (w, h) = (%.3f, %.3f)\n", tgts.targets[i].w, tgts.targets[i].h); // 打印每个目标的置信度 printf(" Object Score = %.3f\n", tgts.targets[i].score); // 打印每个目标的类别,字符串类型 printf(" Object Category = %s, Category ID = [%d]\n", tgts.targets[i].category.c_str(), tgts.targets[i].category_id); // 打印每个目标的视线角,跟相机视场相关 printf(" Object Line-of-sight (ax, ay) = (%.3f, %.3f)\n", tgts.targets[i].los_ax, tgts.targets[i].los_ay); // 打印每个目标的3D位置(在相机坐标系下),跟目标实际长宽、相机参数相关 printf(" Object Position = (x, y, z) = (%.3f, %.3f, %.3f)\n", tgts.targets[i].px, tgts.targets[i].py, tgts.targets[i].pz); p1.x = tgts.targets[i].cx * tgts.width - tgts.targets[i].w * tgts.width / 2; p1.y = tgts.targets[i].cy * tgts.height - tgts.targets[i].h * tgts.height / 2; p2.x = tgts.targets[i].cx * tgts.width + tgts.targets[i].w * tgts.width / 2; p2.y = tgts.targets[i].cy * tgts.height - tgts.targets[i].h * tgts.height / 2; p4.x = tgts.targets[i].cx * tgts.width - tgts.targets[i].w * tgts.width / 2; p4.y = tgts.targets[i].cy * tgts.height + tgts.targets[i].h * tgts.height / 2; p3.x = tgts.targets[i].cx * tgts.width + tgts.targets[i].w * tgts.width / 2; p3.y = tgts.targets[i].cy * tgts.height + tgts.targets[i].h * tgts.height / 2; p.x = pt_origin.x; p.y = pt_origin.y; std::cout << "p.x " << p.x << "\t" << "p.y " << p.y << std::endl; if (getCross(p1, p2, p) * getCross(p3, p4, p) >= 0 && getCross(p2, p3, p) * getCross(p4, p1, p) >= 0) { b_begin_TRACK = false; detect_tracking = false; // pt_origin = cv::Point(nor_x, nor_p_y); // std::cout << "pt_origin " < 0) { printf("Frame-[%d]\n", frame_id); // 打印 跟踪目标 的中心位置,cx,cy的值域为[0, 1] printf(" Tracking Center (cx, cy) = (%.3f, %.3f)\n", tgts.targets[0].cx, tgts.targets[0].cy); // 打印 跟踪目标 的外接矩形框的宽度、高度,w,h的值域为(0, 1] printf(" Tracking Size (w, h) = (%.3f, %.3f)\n", tgts.targets[0].w, tgts.targets[0].h); // 打印 跟踪目标 的视线角,跟相机视场相关 printf(" Tracking Line-of-sight (ax, ay) = (%.3f, %.3f)\n", tgts.targets[0].los_ax, tgts.targets[0].los_ay); } } } // end of tracking // 显示检测结果img cv::imshow(RGB_WINDOW, img); cv::waitKey(10); } return 0; } void onMouse(int event, int x, int y, int, void *) { if (b_clicked) { // 更新框选区域坐标 pt_origin.x = 0; pt_origin.y = 0; } // 左键按下 if (event == cv::EVENT_LBUTTONDOWN) { detect_tracking = true; pt_origin = cv::Point(x, y); } else if (event == cv::EVENT_RBUTTONDOWN) { detect_tracking = true; b_renew_ROI = false; b_begin_TRACK = false; b_clicked = true; } } void GimableCallback(double &frame_ang_r, double &frame_ang_p, double &frame_ang_y, double &imu_ang_r, double &imu_ang_p, double &imu_ang_y, double &fov_x, double &fov_y) { static int count = 0; if (count == 25) { std::cout << "GIMBAL_CMD_RCV_POS" << std::endl; std::cout << "=============================================" << std::endl; std::cout << "HALL_yaw:" << frame_ang_y << " " << std::endl; std::cout << "HALL_roll:" << frame_ang_r << " " << std::endl; std::cout << "HALL_pitch:" << frame_ang_p << " " << std::endl; std::cout << "GYRO_yaw:" << imu_ang_y << " " << std::endl; std::cout << "GYRO_roll:" << imu_ang_r << " " << std::endl; std::cout << "GYRO_pitch:" << imu_ang_p << " " << std::endl; count = 0; } count++; }