请作为资深开发工程师,解释我给出的代码。请逐行分析我的代码并给出你对这段代码的理解。
我给出的代码是:
【#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;
#define Usage() \
{ \
std::cerr << "usage: ./showpic FILE" << std::endl; \
}
#define BAUD 9600
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 fd;
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;
// 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());
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("a", 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 Set_gpio()
{
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范围
}
void Set_duo(int angle)
{
double value = (0.5 + (2.0 / 180.0) * angle) / 20 * 30000; // 100;//20000
cout << "设置舵机" << endl;
gpioPWM(12, value);
}
void Set_dian()
{
cout << "1" << endl;
gpioPWM(13, 12000);
gpioDelay(1000000);
// 第二次启动时,可以注释掉 下面部分
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]);
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;
}
int main()
{
VideoCapture capture;
capture.open(0);//云台摄像头
//capture.open(2);//车前摄像头
if (!capture.isOpened())
{
cout << "Can not open video file!" << endl;
return -1;
}
capture.set(CAP_PROP_FRAME_WIDTH, 320); // opencv设置摄像头参数
capture.set(CAP_PROP_FRAME_HEIGHT, 240); // opencv设置摄像头参数
capture.read(frame);
while (1)
{
capture.read(frame)
imshow("frame", frame);
bool flag1 = crossing(frame);
}
Set_gpio(); // 打开GPIO口
//------------------------------------
std::cout << "Program started" << std::endl;
/*for(int x=12000;x>10000;x-=200){
cout<<x<<endl;
gpioPWM(13,x);
gpioDelay(2000000);
}
while(1);*/
/*while(1){
gpioDelay(1000000);
gpioPWM(13, 11800);
cout<<"start"<<endl;
gpioDelay(1000000);
}*/
//---------------------------------------
char r_buf[1024];
bzero(r_buf, 1024);
fd = uart_open(fd, "/dev/ttyUSB0");/*串口号/dev/ttySn,USB口号/dev/ttyUSBn */
if (fd == -1)
{
fprintf(stderr, "uart_open error\n");
exit(EXIT_FAILURE);
}
if (uart_set(fd, BAUD, 8, 'N', 1) == -1)
{
fprintf(stderr, "uart set failed!\n");
exit(EXIT_FAILURE);
}
while (0)//GPS 陀螺仪,测试时改为1
{
ret = recv_data(fd, 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);
}
// while(1);
gpioPWM(22, 73); //大左小右
gpioPWM(23, 78); //大上下小
Set_duo(90);//大左小右
//if (waitKey(1) == 27){gpioTerminate();break;}
//125
bool duo_flag = 1;
int space = 0;
//while(1);
VideoCapture capture;
capture.open(0);//云台摄像头
//capture.open(2);//车前摄像头
if (!capture.isOpened())
{
cout << "Can not open video file!" << endl;
return -1;
}
capture.set(CAP_PROP_FRAME_WIDTH, 320); // opencv设置摄像头参数
capture.set(CAP_PROP_FRAME_HEIGHT, 240); // opencv设置摄像头参数
capture.read(frame);
int ci = 0;
Rect list;
for (int i = 0; i < 100; i++)
{
capture.read(frame);
}
while (capture.read(frame))
{
ci++;
space++;
if (duo_flag == 1)
Set_duo(90);
if (space >= 50)
duo_flag = 0;
if (ci < 10)
continue;
else
ci = 0;
char key = waitKey(1);
if (key == 27)
break;
imshow("frame", frame); //?
int m;
//m = 1; // 不想识别蓝色挡板时,直接取消注释
if (duo_flag == 0)
{
if (flag_start == false) // 是否还继续识别蓝色挡板(标志位)
{
m = car_start(frame); // 识别蓝色挡板 m==1 时识别到蓝色挡板
if (m == 0)
{
cout << "未识别到蓝色挡板" << endl;
continue;
}
}
else
{
m = 1;
}
int n = 0;
if (m == 1 && n == 0) // 识别到蓝色挡板后
{
if (flag_start == false) // 改变flag_start 的值
{
cout << "123开始启动" << endl;
Set_dian(); // 开启电机
start_ = clock(); // 开始计时
flag_start = true;
}
double error = picture(); // 视觉
Control_Xun(error); // PID控制
//flag_ren = true;
if (flag_ren == false) // 识别一次人行道
{
bool flag1 = crossing(frame); // 是否识别到人行道
if (flag1 == true)
{
cout << "banmaxian" << endl; // 识别到了斑马线
Control_stop(); // 停止车辆
flag_ren = true;
}
}
}
}
}
destroyAllWindows();
system("pause");
exit(EXIT_SUCCESS);
return 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;
Set_duo(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;
Set_duo(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????
}
】
最新发布