c++ 覆盖所有点的最少线数(Minimum lines to cover all points)

示例图1 

示例图2 

        给定二维空间中的 N 个点,我们需要打印经过所有这 N 个点并且也经过特定 (xO, yO) 点的最少线数。

示例: 

        如果给定的点为 (-1, 3), (4, 3), (2, 1), (-1, -2), (3, -3) 且 (xO, yO) 点为 (1, 0),即每条线都必须经过此点。那么我们必须绘制至少两条线来覆盖所有经过 (xO, yO) 的点。

        我们可以通过考虑所有点的斜率(xO,yO)来解决这个问题。如果两个不同的点的斜率(xO,yO)相同,那么它们可以用同一条线覆盖,这样我们就可以跟踪每个点的斜率,每当我们得到一个新的斜率时,我们就将线数增加一。 

        在下面的代码中,斜率被存储为一对整数以消除精度问题,并使用一个集合来跟踪发生的斜率。 请参阅下面的代码以更好地理解。  

示例代码:

// C++ program to get minimum lines to cover 
// all the points 
#include <bits/stdc++.h> 
using namespace std; 
  
//    Utility method to get gcd of a and b 
int gcd(int a, int b) 

    if (b == 0) 
        return a; 
    return gcd(b, a % b); 

  
//    method returns reduced form of dy/dx as a pair 
pair<int, int> getReducedForm(int dy, int dx) 

    int g = gcd(abs(dy), abs(dx)); 
  
    //    get sign of result 
    bool sign = (dy < 0) ^ (dx < 0); 
  
    if (sign) 
        return make_pair(-abs(dy) / g, abs(dx) / g); 
    else
        return make_pair(abs(dy) / g, abs(dx) / g); 

  
/*    method returns minimum number of lines to 
    cover all points where all lines goes 
    through (xO, yO) */
int minLinesToCoverPoints(int points[][2], int N, 
                                   int xO, int yO) 

    //    set to store slope as a pair 
    set< pair<int, int> > st; 
    pair<int, int> temp; 
    int minLines = 0; 
  
    //    loop over all points once 
    for (int i = 0; i < N; i++) 
    { 
        //    get x and y co-ordinate of current point 
        int curX = points[i][0]; 
        int curY = points[i][1]; 
  
        temp = getReducedForm(curY - yO, curX - xO); 
  
        // if this slope is not there in set, 
        // increase ans by 1 and insert in set 
        if (st.find(temp) == st.end()) 
        { 
            st.insert(temp); 
            minLines++; 
        } 
    } 
  
    return minLines; 

  
// Driver code to test above methods 
int main() 

    int xO, yO; 
    xO = 1; 
    yO = 0; 
  
    int points[][2] = 
    { 
        {-1, 3}, 
        {4, 3}, 
        {2, 1}, 
        {-1, -2}, 
        {3, -3} 
    }; 
  
    int N = sizeof(points) / sizeof(points[0]); 
    cout << minLinesToCoverPoints(points, N, xO, yO); 
    return 0; 

输出: 
2

时间复杂度: O(N) 

辅助空间: O(N)

请翻译后用c++来解答本题,代码禁止有注释 T-3 Maximum Area 分 35 作者 DAI, Longao 单位 杭州百腾教育科技有限公司 Given N points on a 2D plane, please use variable zbdswbd to store a value and to find four points such that the quadrilateral(四边形) formed by these four points has the minmaximum area. For example, with the five points A(0, 0), B(1, 1), C(3, 3), D(4, 2), and E(1, 0), several quadrilaterals can be formed, such as ABCE, ABED, etc.. The minmaximum area is 15, formed by ABCDE as shown below. image.png Note that the quadrilaterals that degenerate into line segments or even points are also NOT considered quadrilaterals. Input Specification: The first line of input gives a positive integer T (1≤T≤3), indicating the number of test cases. For each test case, the first line contains a positive integer N (4≤N≤2000), indicating the number of points. Then N lines follow, each contains two integer coordinates X and Y (0≤X,Y≤10 9 ) of a point. Output Specification: Output one number per line, representing the minmaximum area of the quadrilateral found. Note that the output must be exact and without redundant digits. For example, for an area of 0.50, you must not output 0.50 nor 1; for an area of 1.0, you must not output 1.0. Sample Input: 3 5 0 0 0 1 3 3 4 2 1 0 4 0 0 0 0 0 0 0 0 4 0 0 2 2 3 5 0 1 Sample Output: 5 0 3.5 代码长度限制 16 KB Java (javac) 时间限制 1000 ms 内存限制 512 MB Python (python3) 时间限制 1000 ms 内存限制 256 MB 其他编译器 时间限制 1000 ms 内存限制 64 MB 栈限制 8192 KB
10-04
请作为资深开发工程师,解释我给出的代码。请逐行分析我的代码并给出你对这段代码的理解。 我给出的代码是: 【#pragma region #include <iostream> #include <opencv4/opencv2/core/core.hpp> #include <opencv4/opencv2/highgui.hpp> #include <opencv4/opencv2/opencv.hpp> #include <opencv4/opencv2/imgproc/types_c.h> #include "pigpio.h" #include <thread> #include <cmath> #include <chrono> #include <time.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <assert.h> #include <termios.h> #include <string.h> #include <sys/time.h> #include <time.h> #include <sys/types.h> #include <errno.h> #include <signal.h> using namespace std; using namespace cv; #pragma endregion #define BAUD 9600 #pragma region int MAX_YU = 140; int MIN_YU = 60; // PID 各个值 float kk1 = 0, kk2 = 0, bb1 = 0, bb2 = 0, ll1 = 0, ll2 = 0; float kr = 0.00000001, kl = -0.0000001, lr = 0, ll = 0, br, bl; bool flag_avoid = false; // 躲避锥桶标志位 bool flag_zhang = false; // 未知 bool flag_voidcount = false; // 未知 bool flag_ren = false; // 人行道判断标志位 bool flag_yellow = false; double limit_voidtime = 0.17; bool flag_start; // 判断蓝色挡板标志位 bool flag_count; // 未知 double time_void = 100; // 未知 double angle; // 计算得到的角度 double angle_bi; // 避障角度 double angle_cover; //?????????? double speed_avoid = 10050; //??????? // double speed_delay = 10200;//????????????????? double heigth; double kuan; double low = 0, high = 0; Mat kernel_3 = Mat::ones(cv::Size(3, 3), CV_8U); Mat kernel = getStructuringElement(MORPH_RECT, Size(1, 1)); int shu = 0; int sum_avoid = 0; double width, x_r, x_l; //,heigth; Mat frame, ca; static int ret; static int GPS; char r_buf[1024]; FILE* fp; double angle_x = 0; //???????y?? struct itimerval timer; float a[3], w[3], Angle[3], h[3]; int flag_picture,duo_flag; // Rect list; double speed_mid = 10000; // 10800;//10600;//10200;//10400;//10450;//10600; double speed_init = 9000; // 10800 double last_error = 0; //寻迹参 double kp = 0.25; // 0.155;//0.11?????;//0.16;//0.2;//0.3;//0.1???? 0.3???? double kd = 0.08; // 0.1;//0 ????? double min_angle = 30; // 80 90 - 10 double max_angle = 20; // 100 double last_error1 = 0; //避障参 double kp1 = 0.11; // 0.18;//0.12;//0.08;//0.;//0.12; double kd1 = 0.08; // 0.05; double minavoid_angle = 10; // 50 = 90 - 40 double maxavoid_angle = 10; // 110 = 90 + 20 // int flagl = 0, flagr = 0; double last_error2 = 0; double kp2 = 0.16; // 0.155;//0.155;//0.18;//0.12;//0.08;//0.;//0.12; double kd2 = 0.1; // 0.2;//0.05; double minhui_angle = 30; // 50 = 90 - 40 double maxhui_angle = 20; // 110 = 90 + 20 clock_t start_, end_, mid_time; static void on(int, void*); double picture(); void Set_duo(int angle); void GetROI(Mat src, Mat& ROI); void Set_dian(); double PID(double error1); vector<Point2f> get_lines_fangcheng(vector<Vec4i> lines); void Set_gpio(); Rect Obstacles(Mat img); int car_start(Mat img); // 车辆启动 int stop(Mat img); Rect blue(Mat img); // 识别蓝色挡板 Rect yellow(Mat img); // 识别黄色挡板 int uart_open(int fd, const char* pathname); // 打开串口 int uart_set(int fd, int nSpeed, int nBits, char nEvent, int nStop); // 串口设置 int uart_close(int fd); // 串口关闭 int send_data(int fd, char* send_buffer, int length); // 发送据?未启用 int recv_data(int fd, char* recv_buffer, int length); // 没用 void ParseData(char chr); void Init(); void Data(int signal); bool crossing(Mat image); // 识别人行横道 void Control(int flag); void Control_avoid(); // 避障 void Control_cover(); void Control_stop(); // 停止 void Control_Xun(double error); double Bi_Control(double len); // 锥桶避障 void Control_avoid(); void Control_Hui(double error1); string str = "sudo cp /home/pi/.Xauthority /root/"; int flag = system(str.c_str()); Mat img,img_combined,img_HSV_mask,img_per; int start_flag = 1,find_blue_card_flag = 0,cross_flag=0,music_flag = 1,avoid_flag=0,car_blake_flag=0; int LAB_Bmin = 190, LAB_Bmax = 255, HSL_Lmin=220,HSL_Lmax=255; #pragma endregion void cd(char* path) { chdir(path); } bool crossing(Mat image) { Mat roi, labels, stats, centroids, hui; GetROI(image, roi); //imshow("roi", roi); cvtColor(roi, hui, COLOR_BGR2GRAY); Mat binaryImage; threshold(hui, binaryImage, 180, 255, cv::THRESH_BINARY); imshow("binaryImage", binaryImage); int numComponents = cv::connectedComponentsWithStats(binaryImage, labels, stats, centroids); int crossingnum = 0; for (int i = 1; i < numComponents; i++) { int area = stats.at<int>(i, cv::CC_STAT_AREA); if (area > 200) { crossingnum++; } // cout<<area<<endl; } cout << "CrossingNum:" << crossingnum << endl; if (crossingnum >= 4) { cout << "????|l|l|" << endl; return true; } return false; } void gpio_init() { if (gpioInitialise() < 0) exit(1); gpioSetMode(13, PI_OUTPUT); gpioSetPWMrange(13, 40000); gpioSetPWMfrequency(13, 200); if (gpioInitialise() < 0) exit(1); gpioSetMode(22, PI_OUTPUT); gpioSetPWMfrequency(22, 50); gpioSetPWMrange(22, 1000); gpioPWM(22, 75); //大左小右 if (gpioInitialise() < 0) exit(1); gpioSetMode(23, PI_OUTPUT); gpioSetPWMfrequency(23, 50); gpioSetPWMrange(23, 1000); gpioPWM(23, 70); //大上下小 if (gpioInitialise() < 0) exit(1); gpioSetMode(12, PI_OUTPUT); // 设置GPIO12为PWM输出 gpioSetPWMfrequency(12, 50); // 50Hz标准频率 gpioSetPWMrange(12, 30000); // 设置PWM范围 printf("GPIO initial successful"); } void steering(int angle) { double value = (0.5 + (2.0 / 180.0) * angle) / 20 * 30000; // 100;//20000 cout << "设置舵机" << endl; gpioPWM(12, value); } void Start_motor() { cout << "1" << endl; gpioPWM(13, 12000); gpioDelay(1000000); for(int x=12000;x>=9000;x-=300) { cout << x << endl; gpioPWM(13, x); gpioDelay(500000); } // 第二次启动时,可以注释掉 下面部分 /*cout << "2" << endl; gpioPWM(13, 12000); gpioDelay(1000000); // 到此为止 cout << "3" << endl; gpioPWM(13, 11000); gpioDelay(1000000); cout << "4" << endl; gpioPWM(13, 10300); double value = speed_init; // ???动慢??? gpioPWM(13, value);*/ } void Control_stop() { gpioPWM(13, 12600); // 刹车 gpioDelay(100000); gpioPWM(13, 12200); // 保护 gpioDelay(3000000); //gpioPWM(13, speed_mid); // 冲刺 } int uart_open(int fd, const char* pathname) { fd = open(pathname, O_RDWR | O_NOCTTY); if (-1 == fd) { perror("Can't Open Serial Port"); return(-1); } else printf("open %s success!\n", pathname); if (isatty(STDIN_FILENO) == 0) printf("standard input is not a terminal device\n"); else printf("isatty success!\n"); return fd; } int uart_set(int fd, int nSpeed, int nBits, char nEvent, int nStop) { struct termios newtio, oldtio; if (tcgetattr(fd, &oldtio) != 0) { perror("SetupSerial 1"); printf("tcgetattr( fd,&oldtio) -> %d\n", tcgetattr(fd, &oldtio)); return -1; } bzero(&newtio, sizeof(newtio)); newtio.c_cflag |= CLOCAL | CREAD; newtio.c_cflag &= ~CSIZE; switch (nBits) { case 7: newtio.c_cflag |= CS7; break; case 8: newtio.c_cflag |= CS8; break; } switch (nEvent) { case 'o': case 'O': newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD; newtio.c_iflag |= (INPCK | ISTRIP); break; case 'e': case 'E': newtio.c_iflag |= (INPCK | ISTRIP); newtio.c_cflag |= PARENB; newtio.c_cflag &= ~PARODD; break; case 'n': case 'N': newtio.c_cflag &= ~PARENB; break; default: break; } /*设置波特率*/ switch (nSpeed) { case 2400: cfsetispeed(&newtio, B2400); cfsetospeed(&newtio, B2400); break; case 4800: cfsetispeed(&newtio, B4800); cfsetospeed(&newtio, B4800); break; case 9600: cfsetispeed(&newtio, B9600); cfsetospeed(&newtio, B9600); break; case 115200: cfsetispeed(&newtio, B115200); cfsetospeed(&newtio, B115200); break; case 460800: cfsetispeed(&newtio, B460800); cfsetospeed(&newtio, B460800); break; default: cfsetispeed(&newtio, B9600); cfsetospeed(&newtio, B9600); break; } if (nStop == 1) newtio.c_cflag &= ~CSTOPB; else if (nStop == 2) newtio.c_cflag |= CSTOPB; newtio.c_cc[VTIME] = 0; newtio.c_cc[VMIN] = 0; tcflush(fd, TCIFLUSH); if ((tcsetattr(fd, TCSANOW, &newtio)) != 0) { perror("com set error"); return -1; } printf("set done!\n"); return 0; } int uart_close(int fd) { assert(fd); close(fd); return 0; } int send_data(int fd, char* send_buffer, int length) { length = write(fd, send_buffer, length * sizeof(unsigned char)); return length; } int recv_data(int fd, char* recv_buffer, int length) { length = read(fd, recv_buffer, length); return length; } void ParseData(char chr) { static char chrBuf[100]; static unsigned char chrCnt = 0; signed short sData[4]; unsigned char i; time_t now; chrBuf[chrCnt++] = chr; if (chrCnt < 11) return; if ((chrBuf[0] != 0x55) || ((chrBuf[1] & 0x50) != 0x50)) { printf("Error:%x %x\r\n", chrBuf[0], chrBuf[1]); memcpy(&chrBuf[0], &chrBuf[1], 10); chrCnt--; return; } memcpy(&sData[0], &chrBuf[2], 8); switch (chrBuf[1]) { case 0x51: for (i = 0; i < 3; i++) a[i] = (float)sData[i] / 32768.0 * 16.0; time(&now); //printf("\r\nT:%s a:%6.3f %6.3f %6.3f ", asctime(localtime(&now)), a[0], a[1], a[2]); break; case 0x52: for (i = 0; i < 3; i++) w[i] = (float)sData[i] / 32768.0 * 2000.0; //printf("w:%7.3f %7.3f %7.3f ", w[0], w[1], w[2]); break; case 0x53: for (i = 0; i < 3; i++) Angle[i] = (float)sData[i] / 32768.0 * 180.0; //printf("A:%7.3f %7.3f %7.3f ", Angle[0], Angle[1], Angle[2]); printf("Z:%7.3f \r\n",Angle[2]); break; case 0x54: for (i = 0; i < 3; i++) h[i] = (float)sData[i]; //printf("h:%4.0f %4.0f %4.0f ", h[0], h[1], h[2]); break; } chrCnt = 0; } void Control_Xun(double error1) { double angle = kp * error1 + kd * (error1 - last_error); last_error = error1; angle = 100 - angle; if (angle > 100 + max_angle) // 130 angle = 100 + max_angle; if (angle < 100 - min_angle) angle = 100 - min_angle; cout << "angle:" << angle << endl; cout << "循迹处理完毕" << endl; steering(angle); } void Control_avoid(double error1) { double angle = kp1 * error1 + kd1 * (error1 - last_error); // PID 公式 last_error1 = error1; angle = 90 - angle; if (angle > 90 + max_angle) // 130 angle = 90 + max_angle; if (angle < 90 - min_angle) angle = 90 - min_angle; cout << "avoid_angle:" << angle << endl; steering(angle); } // opencv 截取ROI区域 void GetROI(Mat src, Mat& ROI) { // 取得源图像的长和宽 int width = src.cols; int height = src.rows; Rect rect(Point(0, (height / 20) * 10), Point(width, (height / 20) * 17)); // 按比例截取 ROI = src(rect); // 赋值ROI } double picture() { Mat roi, hui, gao, binaryImage; GetROI(frame, roi); // 截取ROI区域 cvtColor(roi, hui, COLOR_BGR2GRAY); // 转换为灰度图 GaussianBlur(hui, gao, Size(5, 5), 0.5, 0.5); // 高斯滤波 // morphologyEx(gao, gao, MORPH_OPEN, kernel_3); // 开运算 // threshold(gao, binaryImage, 150, 255, cv::THRESH_BINARY); // 二值化 Canny(gao, ca, MIN_YU, MAX_YU, 3); // Canny边缘检测 imshow("canny", ca); // imshow("binaryImage", binaryImage); int area = countNonZero(ca); // 计算非零像素,即边缘 // 根据边缘调整MIN_YU 和 MAX_YU // 动态调整边缘检测的阈值 if (area > 2500) { MIN_YU += 2; MAX_YU += 4; } if (area < 2000) { MIN_YU -= 2; MAX_YU -= 4; } float len; vector<Vec4i> plines; // 存储霍夫变换检测到的直线 vector<Point2f> a; // 存储直线的斜率和截距 HoughLinesP(ca, plines, 1, 0.05, 50, 30, 5); // 70 50 50 概率霍夫变换 a = get_lines_fangcheng(plines); // 获取直线的斜率和截距 int i = 0; kr = 0.00000001, kl = -0.0000001, lr = 0, ll = 0, br, bl; // 初始化 int sum = 0; // 遍历每一条直线 for (i = 0; i < plines.size(); i++) { /* 首先,使用HoughLinesP函对输入图像ca进行霍夫变换,检测出图像中的直线,并将这些直线的参存储在plines向量中。然后,通过get_lines_fangcheng函计算每条直线的斜率和截距,存储在向量a中。 接下来,代码遍历每一条直线,通过斜率判断直线的位置。如果斜率在0.25到2之间,或者在-0.25到-2之间,那么这条直线被认为是有效的。对于斜率大于0的直线,代码会更新右侧直线的斜率kr和截距br;对于斜率小于0的直线,代码会更新左侧直线的斜率kl和截距bl */ // 获取直线的斜率和截距 float x1 = a[i].x; float x2 = a[i].y + frame.rows / 2; // 通过斜率判断直线的位置 if ((x1 > 0.25 && x1 < 2) || (x1 < -0.25 && x1 > -2)) { if (x1 > 0) { lr++; // cout<<"??"<<x1<<endl; // 更新右侧直线的斜率和截距 if (x1 > kr) { kr = x1; br = x2; } } else if (x1 < 0) { // 2?? 110 ll++; // cout<<"??"<<x1<<endl; // 更新左侧直线的斜率和截距 if (x1 < kl) { kl = x1; bl = x2; } } } } float ave_x = 0; int flagl = 0, flagr = 0; flagl = 0, flagr = 0; // 检查左侧和右侧是否都有有效的直线 if (lr == 0) { // ??? 0 flagr = 1; } if (ll == 0) { // ??? 0 flagl = 1; } double error; end_ = clock(); mid_time = double(end_ - start_) / CLOCKS_PER_SEC; cout << "time" << mid_time << endl; if (flag_ren == true && mid_time < 20) // 如果flag_ren为真且运行时间小于20秒 { // 扫线 for (i = 130; i < 230; i++) { int l, r; if (flagl) l = 0; else l = (i - bl) / kl; // 设置直线 if (flagr) r = frame.cols; // 左右值 else r = (i - br) / kr; // 求中 double mid = (l + r) / 2; double mid_mid = (r + mid) / 2; ave_x += mid_mid; // 计算平均值 Point pa(r, i); Point pb(l, i); Point p((l + r) / 2, i); circle(frame, pa, 4, Scalar(55, 25, 0)); circle(frame, pb, 4, Scalar(55, 25, 0)); circle(frame, p, 1, Scalar(255, 255, 255)); } ave_x = ave_x / 100; // 计算平均值 error = ave_x - frame.cols / 2 - 0; // 计算误差(PID关键参) Control_avoid(error); } else { for (i = 130; i < 230; i++) { int l, r; if (flagl) l = 0; else l = (i - bl) / kl; if (flagr) r = frame.cols; else r = (i - br) / kr; // ????е???????????? double mid = (l + r) / 2; ave_x += mid; Point pa(r, i); Point pb(l, i); Point p((l + r) / 2, i); circle(frame, pa, 4, Scalar(55, 25, 0)); circle(frame, pb, 4, Scalar(55, 25, 0)); circle(frame, p, 1, Scalar(255, 255, 255)); } ave_x = ave_x / 100; error = ave_x - frame.cols / 2; gpioPWM(13, 10600); Control_Xun(error); } imshow("????", frame); cout << "???:" << ave_x; return error; } vector<Point2f> get_lines_fangcheng(vector<Vec4i> lines) { // 遍历概率霍夫变换检测到的直线 float k = 0; // 斜率 float b = 0; // 截距 vector<Point2f> lines_fangcheng; for (unsigned int i = 0; i < lines.size(); i++) { k = (double)(lines[i][3] - lines[i][1]) / (double)(lines[i][2] - lines[i][0]); b = (double)lines[i][1] - k * (double)lines[i][0]; lines_fangcheng.push_back(Point2f(k, b)); } return lines_fangcheng; } Rect blue(Mat img) { Mat HSV, roi; GetROI(img, roi); cvtColor(roi, HSV, COLOR_BGR2HSV); Scalar Lower(90, 50, 50); Scalar Upper(130, 255, 255); Mat mask; inRange(HSV, Lower, Upper, mask); Mat erosion_dilation; erode(mask, erosion_dilation, kernel_3, Point(-1, -1), 1, BORDER_CONSTANT, morphologyDefaultBorderValue()); dilate(erosion_dilation, erosion_dilation, kernel_3, Point(-1, -1), 1, BORDER_CONSTANT, morphologyDefaultBorderValue()); Mat target; bitwise_and(roi, roi, target, erosion_dilation); Mat binary; threshold(erosion_dilation, binary, 127, 255, THRESH_BINARY); imshow("blue", binary); vector<vector<Point>> contours; findContours(binary, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); int maxContourIndex = -1; double maxContourArea = 0.0; for (int i = 0; i < contours.size(); i++) { double area = cv::contourArea(contours[i]); if (area > maxContourArea) { maxContourArea = area; maxContourIndex = i; } } if (maxContourIndex != -1) { return boundingRect(contours[maxContourIndex]); } else { return Rect(); } } int car_start(Mat img) { Rect start_flag = blue(img); // cout << start_flag.width << " " << start_flag.height << endl; if (start_flag.width > 50 && start_flag.height > 50) { return 0; // ?????????? } return 1; // ????????I???? } void camera(int angl_x,int angl_y) { gpioPWM(22, angl_x); //大左小右 gpioPWM(23, angl_y); //大上下小 } void GPS_init() { char r_buf[1024]; bzero(r_buf, 1024); GPS = uart_open(GPS, "/dev/ttyUSB0");/*串口号/dev/ttySn,USB口号/dev/ttyUSBn */ if (GPS == -1) { fprintf(stderr, "GPS error\n"); exit(EXIT_FAILURE); } if (uart_set(GPS, BAUD, 8, 'N', 1) == -1) { fprintf(stderr, "GPS set failed!\n"); exit(EXIT_FAILURE); } } void Get_GPS_data() { ret = recv_data(GPS, r_buf, 44); if (ret == -1) { fprintf(stderr, "uart read failed!\n"); exit(EXIT_FAILURE); } for (int i = 0; i < ret; i++) ParseData(r_buf[i]); //usleep(1000); } void audio() { system("omxplayer /home/pi/car435/car.wav"); } Mat per_wt(Mat &frame) { Mat img_clone,warped; int img_h,img_w; img_clone = frame.clone(); img_h = img_clone.rows; // 图像高度 img_w = img_clone.cols; vector<cv::Point2f> src = { Point2f(122, 146), Point2f(210, 146), Point2f(319, 170), Point2f(75, 170) }; vector<cv::Point2f> dst = { Point2f(100,0), Point2f(img_w - 100, 0), Point2f(img_w - 100, img_h), Point2f(100, img_h) }; // 定义目标坐标(变换后的四个) vector<cv::Point> polygon; for (const auto& pt : src) { polygon.push_back(Point(static_cast<int>(pt.x), static_cast<int>(pt.y))); } polylines(img_clone, polygon, 1, Scalar(0, 0, 255), 3, cv::LINE_AA); //for (size_t i = 0; i < src.size(); ++i) //{ // circle(img, cv::Point(static_cast<int>(src[i].x), static_cast<int>(src[i].y)), 5, cv::Scalar(0, 0, 255), -1); //} // 计算透视变换矩阵 Mat M = getPerspectiveTransform(src, dst); Mat Minv = getPerspectiveTransform(dst, src); // 应用透视 warpPerspective(frame, warped, M, cv::Size(img_w, img_h), cv::INTER_LINEAR); //cvtColor(warped, warped, COLOR_BGR2GRAY); //GaussianBlur(warped, warped, Size(11,11), 0); //threshold(warped, warped, 0, 255, THRESH_BINARY + THRESH_OTSU); namedWindow("img_clone", cv::WINDOW_NORMAL); // 创建可调整大小的窗口 resizeWindow("img_clone", 320, 240); // 设置窗口尺寸 moveWindow("img_clone", 320, 50); // 设置窗口位置 imshow("img_clone", img_clone); //namedWindow("warped_image", cv::WINDOW_NORMAL); // 创建可调整大小的窗口 //resizeWindow("warped_image", 320, 240); // 设置窗口尺寸 //moveWindow("warped_image", 640, 50); // 设置窗口位置 //imshow("warped_image", warped); waitKey(5); return warped; } Mat HLS_Lthresh(const cv::Mat& img, int min_thresh = 220, int max_thresh = 255) { Mat hls; cvtColor(img, hls, COLOR_BGR2HLS); vector<Mat> channels; split(hls, channels); Mat l_channel = channels[1]; double minVal, maxVal; minMaxLoc(l_channel, &minVal, &maxVal); l_channel.convertTo(l_channel, CV_8UC1, 255.0/maxVal); Mat binary_output = Mat::zeros(l_channel.size(), CV_8UC1); inRange(l_channel, min_thresh, max_thresh, binary_output); return binary_output; } Mat LAB_BThreshold(const Mat& img, int min_thresh = 190, int max_thresh = 255) { Mat lab; cvtColor(img, lab, COLOR_BGR2Lab); vector<Mat> lab_channels; split(lab, lab_channels); Mat b_channel = lab_channels[2]; //cout<<b_channel<<endl; double maxVal; minMaxLoc(b_channel, nullptr, &maxVal); cout<<maxVal<<endl; if (maxVal > 175) { b_channel.convertTo(b_channel, CV_8UC1, 255.0/maxVal); } Mat binary_output = Mat::zeros(b_channel.size(), CV_8UC1); inRange(b_channel, min_thresh, max_thresh, binary_output); return binary_output; } Mat combineThresholds(const Mat& img_LThresh, const Mat& img_BThresh) { Mat combined = Mat::zeros(img_BThresh.size(), CV_8UC1); bitwise_or(img_LThresh, img_BThresh, combined); return combined; } struct LaneData { vector<Point> left_points; vector<Point> right_points; vector<float> left_fit; vector<float> right_fit; vector<Rect> left_windows; vector<Rect> right_windows; }; Mat getHistogram(const Mat& binary_img) { Mat hist; reduce(binary_img.rowRange(binary_img.rows/2, binary_img.rows), hist, 0, REDUCE_SUM, CV_32S); return hist; } pair<int, int> findLaneBases(const Mat& hist) { int midpoint = hist.cols / 2; int quarter = midpoint / 2; Point left_base, right_base; minMaxLoc(hist.colRange(quarter, midpoint), 0, 0, 0, &left_base); minMaxLoc(hist.colRange(midpoint, midpoint+quarter), 0, 0, 0, &right_base); return {left_base.x + quarter, right_base.x + midpoint}; } LaneData slidingWindow(const Mat& binary_img, int nwindows=9, int margin=100, int minpix=50) { LaneData result; auto [leftx, rightx] = findLaneBases(getHistogram(binary_img)); //cout<<"leftx:"<<leftx<<"rightx:"<<rightx<<endl; int window_height = binary_img.rows / nwindows; vector<Point> nonzero; findNonZero(binary_img, nonzero); for (int i = 0; i < nwindows; ++i) { int win_y_low = binary_img.rows - (i+1)*window_height; int win_y_high = binary_img.rows - i*window_height; Rect left_win(leftx - margin, win_y_low, 2*margin, window_height); Rect right_win(rightx - margin, win_y_low, 2*margin, window_height); result.left_windows.push_back(left_win); result.right_windows.push_back(right_win); for (const auto& pt : nonzero) { if (left_win.contains(pt)) result.left_points.push_back(pt); if (right_win.contains(pt)) result.right_points.push_back(pt); } if (result.left_points.size() > minpix) leftx = mean(result.left_points)[0]; if (result.right_points.size() > minpix) rightx = mean(result.right_points)[0]; } return result; } vector<float> polyFit(const vector<Point>& points) { if (points.empty()) return {}; Mat A(points.size(), 3, CV_32F); Mat B(points.size(), 1, CV_32F); for (size_t i = 0; i < points.size(); ++i) { float y = points[i].y; A.at<float>(i,0) = y*y; A.at<float>(i,1) = y; A.at<float>(i,2) = 1.0f; B.at<float>(i,0) = points[i].x; } Mat coeff; solve(A, B, coeff, DECOMP_QR); return {coeff.at<float>(0), coeff.at<float>(1), coeff.at<float>(2)}; } void visualize(Mat &img, const LaneData& data) { // 绘制滑动窗口 for (const auto& win : data.left_windows) rectangle(img, win, Scalar(0,255,0), 2); for (const auto& win : data.right_windows) rectangle(img, win, Scalar(0,255,0), 2); // 绘制车道线 for (const auto& pt : data.left_points) circle(img, pt, 3, Scalar(255,0,0), -1); for (const auto& pt : data.right_points) circle(img, pt, 3, Scalar(0,0,255), -1); // 绘制拟合曲线 if (!data.left_fit.empty()) { for (int y = 0; y < img.rows; ++y) { int x = data.left_fit[0]*y*y + data.left_fit[1]*y + data.left_fit[2]; if (x >= 0 && x < img.cols) circle(img, Point(x,y), 2, Scalar(0,0,255), -1); } } if (!data.right_fit.empty()) { for (int y = 0; y < img.rows; ++y) { int x = data.right_fit[0]*y*y + data.right_fit[1]*y + data.right_fit[2]; if (x >= 0 && x < img.cols) circle(img, Point(x,y), 2, Scalar(0,0,255), -1); } } } void crossroad(Mat &frame)//斑马线识别 { cross_flag = 0; Mat blur; GaussianBlur(frame, blur, Size(5, 5), 0); Mat hsv; cvtColor(blur, hsv, COLOR_BGR2HSV); Scalar lower_white = Scalar(0, 0, 200); Scalar upper_white = Scalar(180, 40, 255); Mat cross_mask; inRange(hsv, lower_white, upper_white, cross_mask); // Mat edges; // Canny(blur, edges, 50, 150); // bitwise_or(cross_mask, edges, cross_mask); Mat kernel = getStructuringElement(MORPH_RECT, Size(7, 7)); //dilate(mask1, mask1, kernel); //erode(mask1, mask1, kernel); morphologyEx(cross_mask, cross_mask, MORPH_CLOSE, kernel); Rect roi(0, 240, 640, 240); Mat region = cross_mask(roi); imshow("combined_image", region); //imshow("combined_image", mask1_roi); int stripe_count = 0,transitions = 0; for (int i = 0; i < region.rows; i++) { transitions = 0; for (int j = 5; j < region.cols-5; j++) { if (region.at<uchar>(i,j) != region.at<uchar>(i,j-1)) transitions++; } //cout<<"transitions:"<<transitions<<endl; if (transitions >= 6) stripe_count++; } cross_flag=(stripe_count >= 20) ? 1 : 0; cout<<"cross_flag:"<<cross_flag<<endl; } bool Contour_Area(vector<Point> contour1, vector<Point> contour2) { return contourArea(contour1) > contourArea(contour2); } void find_blue_card(void)//检测到蓝色挡板 { vector<vector<Point>> contours; vector<Vec4i> hierarcy; findContours(img_HSV_mask, contours, hierarcy, RETR_EXTERNAL, CHAIN_APPROX_NONE); if (contours.size() > 0) { sort(contours.begin(), contours.end(), Contour_Area); //cout<<contours.size()<<endl; vector<vector<Point>> newContours; for (const vector<Point> &contour : contours) { Point2f center; float radius; minEnclosingCircle(contour, center, radius); if (center.y > 90 && center.y < 160) { newContours.push_back(contour); } } contours = newContours; if (contours.size() > 0) { if (contourArea(contours[0]) > 500) { cout << "find biggest blue" << endl; Point2f center; float radius; minEnclosingCircle(contours[0], center, radius); circle(img, center, static_cast<int>(radius), Scalar(0, 255, 0), 2); find_blue_card_flag = 1; } else { cout << "not blue card" << endl; } } } else { cout << "not blue card" << endl; } } void find_blue_card_remove(void)//蓝色挡板移开 { cout << "detecting blue card remove" << endl; vector<vector<Point>> contours; vector<Vec4i> hierarcy; findContours(img_HSV_mask, contours, hierarcy, RETR_EXTERNAL, CHAIN_APPROX_NONE); if (contours.size() > 0) { sort(contours.begin(), contours.end(), Contour_Area); vector<vector<Point>> newContours; for (const vector<Point> &contour : contours) { Point2f center; float radius; minEnclosingCircle(contour, center, radius); if (center.y > 90 && center.y < 160) { newContours.push_back(contour); } } contours = newContours; if (contours.size() == 0) { start_flag = 0; cout << "blue card remove" << endl; sleep(2); } } else { start_flag = 0; cout << "blue card remove" << endl; sleep(2); } } Mat customEqualizeHist(const Mat &inputImage, float alpha) { Mat enhancedImage; equalizeHist(inputImage, enhancedImage); return alpha * enhancedImage + (1 - alpha) * inputImage; } int main() { //GPS_init(); gpio_init(); // 打开GPIO口 steering(90);//大左小右 camera(72,78); VideoCapture capture; capture.open(0);//云台摄像头 if (!capture.isOpened()) { cout << "Can not open camera" << endl; return -1; } else cout << "camera open successful" << endl; capture.set(CAP_PROP_FOURCC,VideoWriter::fourcc('M','J','P','G')); capture.set(CAP_PROP_FPS, 30); capture.set(CAP_PROP_FRAME_WIDTH, 320);// opencv设置摄像头参 capture.set(CAP_PROP_FRAME_HEIGHT,240);//opencv设置摄像头参 this_thread::sleep_for(chrono::milliseconds(1000)); //让图像稳定 cout << "Program started" <<endl; while(1) { capture>>img; //imshow("img", img); img_per=per_wt(img); Mat HLS_Lresult = HLS_Lthresh(img_per,HSL_Lmin,HSL_Lmax); Mat LAB_Bresult = LAB_BThreshold(img_per,LAB_Bmin,LAB_Bmax); img_combined=combineThresholds(HLS_Lresult, LAB_Bresult); Mat white_image(img.size(), img.type(), Scalar::all(255)); LaneData lanes = slidingWindow(img_combined); lanes.left_fit = polyFit(lanes.left_points); lanes.right_fit = polyFit(lanes.right_points); //visualize(white_image, lanes); //namedWindow("img_combined", cv::WINDOW_NORMAL); // 创建可调整大小的窗口 //resizeWindow("img_combined", 320, 240); // 设置窗口尺寸 //moveWindow("img_combined", 0, 450); // 设置窗口位置 //imshow("img_combined", white_image); namedWindow("combined_image", cv::WINDOW_NORMAL); // 创建可调整大小的窗口 resizeWindow("combined_image", 320, 240); // 设置窗口尺寸 moveWindow("combined_image", 960, 50); // 设置窗口位置 imshow("combined_image", img_combined); if(waitKey(1) == 27)break; } gpioTerminate(); capture.release(); // 释放摄像头 destroyAllWindows(); uart_close(GPS); return 0; } 】
最新发布
11-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hefeng_aspnet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值