// /*car*/
// #include <ros/ros.h>
// #include <image_transport/image_transport.h>
// #include <cv_bridge/cv_bridge.h>
// #include <sensor_msgs/image_encodings.h>
// #include <opencv2/opencv.hpp>
// #include <iostream>
// #include <ros/package.h>
// #include <string>
// #include <vector>
// #include <map>
// #include <set>
// using namespace cv;
// using namespace std;
// // 定义全局变量
// static int max_value = 255;
// static int min_value = 0;
// static int gray_2_canny_max = 230;
// static int gray_2_canny_min= 200;
// static Mat car_Image;
// struct Line {
// int x1, y1, x2, y2;
// // 定义 operator< 运算符
// bool operator<(const Line& other) const {
// if (x1 != other.x1) {
// return x1 < other.x1;
// }
// if (y1 != other.y1) {
// return y1 < other.y1;
// }
// if (x2 != other.x2) {
// return x2 < other.x2;
// }
// return y2 < other.y2;
// }
// };
// // 定义一个函数用于绘制停车位
// std::pair<cv::Mat, std::map<std::tuple<int, int, int, int>, int>> draw_parking
// (
// const cv::Mat& image,
// const std::map<int, std::vector<int>>& rects,
// bool make_copy = true
// )
// {
// cv::Mat new_image;
// if (make_copy) {
// new_image = image.clone();
// } else {
// new_image = image;
// }
// double gap = 15.5;
// std::map<std::tuple<int, int, int, int>, int> spot_dict;
// int tot_spots = 0;
// // 微调参数
// std::map<int, int> adj_x1 = {
// {0, -8}, {1, -15}, {2, -15}, {3, -15}, {4, -15}, {5, -15}, {6, -15}, {7, -15}, {8, -10}, {9, -10}, {10, -10}, {11, 0}
// };
// std::map<int, int> adj_x2 = {
// {0, 0}, {1, 15}, {2, 15}, {3, 15}, {4, 15}, {5, 15}, {6, 15}, {7, 15}, {8, 10}, {9, 10}, {10, 10}, {11, 0}
// };
// std::map<int, int> fine_tune_y = {
// {0, 4}, {1, -2}, {2, 3}, {3, 1}, {4, -3}, {5, 1}, {6, 5}, {7, -3}, {8, 0}, {9, 5}, {10, 4}, {11, 0}
// };
// for (const auto& pair : rects) {
// int key = pair.first;
// const std::vector<int>& tup = pair.second;
// int x1 = static_cast<int>(tup[0] + adj_x1[key]);
// int x2 = static_cast<int>(tup[2] + adj_x2[key]);
// int y1 = static_cast<int>(tup[1]);
// int y2 = static_cast<int>(tup[3]);
// // 绘制矩形
// cv::rectangle(new_image, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 255, 0), 2);
// int num_splits = static_cast<int>(std::abs(y2 - y1) / gap);
// for (int i = 0; i <= num_splits; ++i) {
// int y = static_cast<int>(y1 + i * gap) + fine_tune_y[key];
// // 绘制横线
// cv::line(new_image, cv::Point(x1, y), cv::Point(x2, y), cv::Scalar(255, 0, 0), 2);
// }
// if (key > 0 && key < rects.size() - 1) {
// int x = static_cast<int>((x1 + x2) / 2);
// // 绘制竖线
// cv::line(new_image, cv::Point(x, y1), cv::Point(x, y2), cv::Scalar(0, 0, 255), 2);
// }
// // 计算停车位数量
// if (key == 0 || key == rects.size() - 1) {
// tot_spots += num_splits + 1;
// } else {
// tot_spots += 2 * (num_splits + 1);
// }
// // 填充车位字典
// if (key == 0 || key == rects.size() - 1) {
// for (int i = 0; i <= num_splits; ++i) {
// int cur_len = static_cast<int>(spot_dict.size());
// int y = static_cast<int>(y1 + i * gap) + fine_tune_y[key];
// spot_dict[std::make_tuple(x1, y, x2, y + static_cast<int>(gap))] = cur_len + 1;
// }
// } else {
// for (int i = 0; i <= num_splits; ++i) {
// int cur_len = static_cast<int>(spot_dict.size());
// int y = static_cast<int>(y1 + i * gap) + fine_tune_y[key];
// int x = static_cast<int>((x1 + x2) / 2);
// spot_dict[std::make_tuple(x1, y, x, y + static_cast<int>(gap))] = cur_len + 1;
// spot_dict[std::make_tuple(x, y, x2, y + static_cast<int>(gap))] = cur_len + 2;
// }
// }
// }
// return std::make_pair(new_image, spot_dict);
// }
// // rect_finetune 函数的 C++ 实现
// std::pair<cv::Mat, std::map<int, std::vector<int>>> rect_finetune(
// const cv::Mat& image,
// std::map<int, std::vector<int>> rects,
// bool copy_img = true)
// {
// cv::Mat image_copy;
// if (copy_img) {
// image_copy = image.clone();
// }
// // 对矩形框的坐标进行微调
// for (auto& pair : rects) {
// int k = pair.first;
// std::vector<int>& rect = pair.second;
// if (k == 0) {
// rect[1] -= 10;
// }
// else if (k == 1) {
// rect[1] -= 10;
// rect[3] += 10;
// }
// else if (k == 3) {
// rect[1] += 110;
// rect[3] += 60;
// }
// else if (k == 4) {
// rect[1] += 150;
// rect[3] += 60;
// }
// else if (k == 5) {
// rect[1] += 80;
// rect[3] += 13;
// }
// else if (k == 2) {
// rect[1] -= 4;
// rect[3] += 13;
// }
// else if (k == 6 || k == 8) {
// rect[1] -= 18;
// rect[3] += 12;
// }
// else if (k == 9) {
// rect[1] += 10;
// rect[3] += 10;
// }
// else if (k == 10) {
// rect[1] += 45;
// }
// else if (k == 11) {
// rect[3] += 45;
// }
// }
// int buff = 8;
// for (const auto& pair : rects) {
// int key = pair.first;
// const std::vector<int>& rect = pair.second;
// cv::Point tup_topLeft(rect[0] - buff, rect[1]);
// cv::Point tup_botRight(rect[2] + buff, rect[3]);
// cv::rectangle(image_copy, tup_topLeft, tup_botRight, cv::Scalar(0, 255, 0), 3);
// }
// return std::make_pair(image_copy, rects);
// }
// // 定义比较函数,用于按 x1 和 y1 排序直线
// bool compareLines(const Line& a, const Line& b) {
// if (a.x1 != b.x1) {
// return a.x1 < b.x1;
// }
// return a.y1 < b.y1;
// }
// // 定义比较函数,用于按 y1 排序直线
// bool compareLinesByY(const Line& a, const Line& b) {
// return a.y1 < b.y1;
// }
// // identity_blocks 函数,实现与 Python 代码相同的功能
// //pair实质上是一个结构体 pair.first/pair.second
// std::pair<cv::Mat, std::map<int, std::vector<int>>> identity_blocks(const cv::Mat& image, const std::vector<std::vector<int>>& lines, bool make_copy = true) {
// cv::Mat new_image;
// if (make_copy) {
// new_image = image.clone();
// }
// // 过滤部分直线
// std::vector<Line> stayed_lines;
// for (const auto& line : lines) {
// int x1 = line[0], y1 = line[1], x2 = line[2], y2 = line[3];
// if (std::abs(y2 - y1) <= 1 && std::abs(x2 - x1) >= 25 && std::abs(x2 - x1) <= 55) {
// Line line = {x1, y1, x2, y2};
// stayed_lines.push_back(line);
// /*or
// stayed_lines.emplace_back(x1, y1, x2, y2);
// */
// }
// }
// // 对直线按照 x1 排序
// std::sort(stayed_lines.begin(), stayed_lines.end(), compareLines);
// // 找到多个列,相当于每列是一排车
// std::map<int, std::vector<Line>> clusters;//std::map 会根据键的大小自动对元素进行排序
// int dIndex = 0;
// int clus_dist = 10; // 每一列之间的那个距离
// for (size_t i = 0; i < stayed_lines.size() - 1; ++i) //for 循环的迭代部分并不依赖于自增运算符的返回值++i=i++
// {
// int distance = std::abs(stayed_lines[i + 1].x1 - stayed_lines[i].x1);
// if (distance <= clus_dist) {
// /*map_use*/
// clusters[dIndex].push_back(stayed_lines[i]);
// clusters[dIndex].push_back(stayed_lines[i + 1]);
// } else {
// ++dIndex;
// }
// }
// //duanduanduanduanduanduanduanduanduanduan
// // 得到每列停车位的矩形框
// std::map<int, std::vector<int>> rects;
// int i = 0;
// for (const auto& cluster : clusters) {
// std::vector<Line> all_list = cluster.second;
// /*
// 通过这个范围(all_list.begin(), all_list.end())初始化,
// std::set 会遍历该范围内的所有 Line 对象,将它们插入到 unique_lines 中。
// 在插入过程中,std::set 会自动去重(即如果有重复的 Line 对象,只会保留一个),并根据比较规则对元素进行排序
// */
// std::set<Line> unique_lines(all_list.begin(), all_list.end());//set:去重+排序
// //std::set<Line> 容器 unique_lines 中的元素复制到一个 std::vector<Line> 容器 cleaned 中
// std::vector<Line> cleaned(unique_lines.begin(), unique_lines.end());
// // 有 5 个停车位至少
// if (cleaned.size() > 5) {
// std::sort(cleaned.begin(), cleaned.end(), compareLinesByY);
// int avg_y1 = cleaned[0].y1;
// int avg_y2 = cleaned.back().y1;
// if (std::abs(avg_y2 - avg_y1) < 15) {
// continue;
// }
// double avg_x1 = 0, avg_x2 = 0;
// for (const auto& tup : cleaned) {
// avg_x1 += tup.x1;
// avg_x2 += tup.x2;
// }
// avg_x1 /= cleaned.size();
// avg_x2 /= cleaned.size();
// rects[i] = {static_cast<int>(avg_x1), avg_y1, static_cast<int>(avg_x2), avg_y2};
// ++i;
// }
// }
// std::cout << "Num Parking Lanes: " << rects.size() << std::endl;
// // 把列矩形画出来
// int buff = 7;
// for (const auto& rect : rects) {
// cv::Point tup_topLeft(rect.second[0] - buff, rect.second[1]);
// cv::Point tup_botRight(rect.second[2] + buff, rect.second[3]);
// cv::rectangle(new_image, tup_topLeft, tup_botRight, cv::Scalar(0, 255, 0), 3);
// }
// return std::make_pair(new_image, rects);//之前没有创建pair对象,所以这里临时创建对象返回
// }
// // 在图像上绘制直线并筛选
// cv::Mat draw_lines(const cv::Mat& image,
// const std::vector<cv::Vec4i>& lines,
// cv::Scalar color = cv::Scalar(255, 0, 0),
// int thickness = 1,
// bool make_copy = true) {
// cv::Mat result;
// if (make_copy) {
// image.copyTo(result);
// } else {
// result = const_cast<cv::Mat&>(image);
// }
// std::vector<cv::Vec4i> cleaned;
// for (const cv::Vec4i& line : lines) {
// int x1 = line[0];
// int y1 = line[1];
// int x2 = line[2];
// int y2 = line[3];
// if (abs(y2 - y1) <= 1 && abs(x2 - x1) >= 25 && abs(x2 - x1) <= 55) {
// cleaned.push_back(line);
// cv::line(result, cv::Point(x1, y1), cv::Point(x2, y2), color, thickness);
// }
// }
// return result;
// }
// // 定义hough_lines函数
// std::vector<cv::Vec4i> hough_lines(const cv::Mat& image) {
// std::vector<cv::Vec4i> lines;
// // 调用HoughLinesP函数进行直线检测
// cv::HoughLinesP(image, lines, 0.1, CV_PI / 10, 15, 9, 4);
// return lines;
// }
// // 函数用于根据顶点区域过滤图像
// cv::Mat filter_region(const cv::Mat& image, const std::vector<cv::Point>& vertices) {
// cv::Mat mask = cv::Mat::zeros(image.size(), image.type());
// if (image.channels() == 1) {
// std::vector<std::vector<cv::Point>> contours;
// contours.push_back(vertices);
// cv::fillPoly(mask, contours, cv::Scalar(255));
// cv::imshow("mask", mask);
// } else {
// std::vector<std::vector<cv::Point>> contours;
// contours.push_back(vertices);
// cv::fillPoly(mask, contours, cv::Scalar(255, 255, 255));
// }
// cv::Mat result;
// cv::bitwise_and(image, mask, result);
// return result;
// }
// cv::Mat select_region(const cv::Mat& image) {
// int rows = image.rows;
// int cols = image.cols;
// cv::Point pt_1 = cv::Point(cols * 0.05, rows * 0.90);
// cv::Point pt_2 = cv::Point(cols * 0.05, rows * 0.70);
// cv::Point pt_3 = cv::Point(cols * 0.30, rows * 0.55);
// cv::Point pt_4 = cv::Point(cols * 0.30, rows * 0.15);
// cv::Point pt_5 = cv::Point(cols * 0.90, rows * 0.15);
// cv::Point pt_6 = cv::Point(cols * 0.90, rows * 0.90);
// std::vector<cv::Point> vertices = {pt_1, pt_2, pt_3, pt_4, pt_5, pt_6};
// cv::Mat point_img = image.clone();
// if (point_img.channels() == 1) {
// cv::cvtColor(point_img, point_img, cv::COLOR_GRAY2RGB);
// }
// for (const cv::Point& point : vertices) {
// cv::circle(point_img, point, 10, cv::Scalar(0, 0, 255), 4);
// }
// cv::imshow("point_img", point_img);
// return filter_region(image, vertices);
// }
// // 滑动条值改变的回调函数
// void onTrackbarChange(int, void*) {
// // 第一种方法:灰度化和二值化
// Mat gray;
// cvtColor(car_Image, gray, COLOR_BGR2GRAY);
// Mat binary;
// threshold(gray, binary, min_value, max_value, THRESH_BINARY);
// cv::imshow("binary", binary);
// // 第二种方法:颜色范围过滤
// cv::Scalar low(120, 120, 120); // BGR
// cv::Scalar upper(255, 255, 255);
// cv::Mat white_img;
// cv::inRange(car_Image, low, upper, white_img);
// cv::imshow("white_img", white_img);
// // 与原图进行与运算,求出结果图像 有点没必要
// cv::Mat and_img;
// cv::bitwise_and(car_Image, car_Image, and_img, white_img);
// cv::imshow("and_img", and_img);
// Mat gray_2;
// cvtColor(and_img, gray_2, COLOR_BGR2GRAY);
// cv::imshow("gray_2", gray_2);
// // 进行Canny边缘检测 直接在灰度图像gray_2上进行边缘检测
// cv::Mat edges;
// cv::Canny(gray_2, edges, gray_2_canny_min, gray_2_canny_max); //230-250 I CAN change
// cv::imshow("edges", edges);
// cv::Mat result = select_region(edges);
// cv::imshow("result", result);
// std::vector<cv::Vec4i> detectedLines = hough_lines(result);
// cv::Mat outputImage = draw_lines(car_Image, detectedLines);
// // 将检测到的直线转换为 identity_blocks 函数所需的格式
// std::vector<std::vector<int>> linesForIdentityBlocks;
// for (const auto& line : detectedLines) {
// linesForIdentityBlocks.push_back({line[0], line[1], line[2], line[3]});//<cv::Vec4i>好
// }
// // 调用 identity_blocks 函数
// auto [newImageWithRects, rects] = identity_blocks(outputImage, linesForIdentityBlocks);
// cv::imshow("Image with drawn lines and rectangles", newImageWithRects);
// auto [newImageWithRects_2, rects_2]=rect_finetune(car_Image,rects) ;
// cv::imshow("Image with drawn lines and rectangles__2", newImageWithRects_2);
// auto[newImageWithRects_3, spot_dict]=draw_parking(car_Image,rects_2);
// cv::imshow("Image with drawn lines and rectangles__3", newImageWithRects_3);
// }
// int main(int argc, char** argv) {
// ros::init(argc, argv, "demo_cv_hsv");
// ros::NodeHandle nh;
// // 获取当前功能包的路径
// string packagePath = ros::package::getPath("wpr_simulation");
// // 构建包含数字的图像路径(数字模板图像)
// string car_path = packagePath + "/data/car.png";
// // 读取数字模板图像
// car_Image = imread(car_path, IMREAD_COLOR);
// if (car_Image.empty()) {
// ROS_ERROR("无法读取数字模板图像,请检查图像路径。");
// return -1;
// }
// // 生成图像显示和参数调节的窗口空间
// cv::namedWindow("WINDOW", cv::WINDOW_AUTOSIZE);
// cv::createTrackbar("max", "WINDOW", &max_value, 255, onTrackbarChange);
// cv::createTrackbar("min", "WINDOW", &min_value, 255, onTrackbarChange);
// cv::createTrackbar("gray_2_canny_min", "WINDOW", &gray_2_canny_min, 255, onTrackbarChange);
// cv::createTrackbar("gray_2_canny_max", "WINDOW", &gray_2_canny_max, 255, onTrackbarChange);
// // 初始调用回调函数以显示初始图像
// onTrackbarChange(0, nullptr);
// imshow("car_Image", car_Image);
// waitKey(0);
// ros::Rate loop_rate(50);
// while (ros::ok()) {
// ros::spinOnce();
// loop_rate.sleep();
// }
// return 0;
// }