Advertisement
Cai_B

RGBYK Line Following Solution

Apr 21st, 2024 (edited)
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.08 KB | None | 0 0
  1. #include <stdio.h>
  2. //#include <ctime.h>
  3.  
  4. #include "opencv_aee.hpp"
  5. #include "main.hpp" // You can use this file for declaring defined values and functions
  6. #include "pi2c.h"
  7.  
  8. using namespace cv;
  9. using namespace std;
  10.  
  11. Pi2c car(0x22); // Configure the I2C interface to the Car as a global variable
  12.  
  13. void setup(void)
  14. {
  15.     setupCamera(320, 240); // Enable the camera for OpenCV
  16. }
  17. Mat resizeimage(Mat shape,int resize_method)
  18. {
  19.     Mat resized_image;
  20.     resize(shape, resized_image, Size(320, 240), 0.0, 0.0, resize_method);
  21.  
  22.     return resized_image;
  23. }
  24. Mat blackandwhite(Mat resized_image)
  25. {
  26.     Mat image_HSV;
  27.     Mat image_GREY;
  28.  
  29.     cvtColor(resized_image, image_HSV, COLOR_BGR2HSV); // Convert the image to HSV
  30.     inRange(image_HSV, Scalar(128, 50, 50), Scalar(179, 255, 255), image_GREY);
  31.  
  32.     return image_GREY;
  33.  
  34. }
  35.  
  36. // Function to send updated Servo angle along with Left and Right Motor Speeds to the Slave ESP32 from the Pi
  37. void I2C(int16_t leftmotor,int16_t rightmotor,int16_t servoangle)
  38. {
  39.     char data[6];
  40.     data[0] = (leftmotor >> 8)& 0xFF;   // leftMotor_speed16_9
  41.     data[1] = leftmotor & 0xFF;       // leftMotor_speed8_1
  42.     data[2] = (rightmotor >> 8)& 0xFF;  // rightMotor_speed16_9
  43.     data[3] = rightmotor & 0xFF;         // rightMotor_speed8_1
  44.     data[4] = (servoangle >> 8) & 0xFF;        // servoAngle16_9
  45.     data[5] = servoangle & 0xFF;               // servoAngle8_1
  46.  
  47.     car.i2cWrite(data, 6);
  48. }
  49.  
  50.  
  51. int main(int argc, char** argv)
  52. {
  53.     setup(); // Call a setup function to prepare IO and devices
  54.  
  55.     float kp =70;
  56.     float ki =1.2;
  57.     float kd =1.3;
  58.  
  59.     float pinkcompare=0;
  60.     float linecompare=0;
  61.  
  62.     float setpoint=0;
  63.     float error=0;
  64.     float previouserror=0;
  65.     float totalerror=0;
  66.     float u=0;
  67.  
  68.     int servoangle=90;
  69.     int centreangle=80;
  70.  
  71.     int16_t leftmotor =90;
  72.     int16_t rightmotor=90;
  73.  
  74.     // Intalises HSV variables to Isolate black pixels from the black line it follows intially
  75.     int Hlow=0;
  76.     int Hhigh=180;
  77.     int Slow=0;
  78.     int Shigh=102;
  79.     int Vlow=0;
  80.     int Vhigh=64;
  81.  
  82.  
  83.    // int counter=0;
  84.     // const clock_t start = clock();
  85.     //int currentTime = 0;
  86.     //const int delay = 3;
  87.     Mat triangle;
  88.     Mat circle;
  89.     Mat star;
  90.     Mat umbrella;
  91.     Mat comparator;
  92.     Mat linecomparator;
  93.  
  94.     triangle = imread("/home/B01-20/Desktop/OpenCV-Template/Triangle (Blue Line).png");
  95.     circle= imread("/home/B01-20/Desktop/OpenCV-Template/Circle (Red Line).png");
  96.     star=imread("/home/B01-20/Desktop/OpenCV-Template/Star (Green Line).png");
  97.     umbrella=imread("/home/B01-20/Desktop/OpenCV-Template/Umbrella (Yellow Line).png");
  98.     comparator=imread("/home/B01-20/Desktop/OpenCV-Template/Black_Image.png"); // Comparator image used to check of there is a symbol or line present in either of the frames
  99.  
  100.     double orig_aspect = triangle.cols / static_cast<double>(triangle.rows);
  101.     double target_aspect = 320.0 / 240.0;
  102.     int resize_method = orig_aspect > target_aspect ? INTER_AREA : INTER_CUBIC;
  103.  
  104.     triangle=resizeimage(triangle,resize_method);
  105.     circle=resizeimage(circle,resize_method);
  106.     star=resizeimage(star,resize_method);
  107.     umbrella=resizeimage(umbrella,resize_method);
  108.     comparator=resizeimage(comparator,resize_method); // Reizes the comparator image to the size of the frame
  109.  
  110.  
  111.     triangle= blackandwhite(triangle);
  112.     circle= blackandwhite(circle);
  113.     star= blackandwhite(star);
  114.     umbrella= blackandwhite(umbrella);
  115.     while (1)   // Main loop to perform image processing
  116.     {
  117.  
  118.         Mat frame;
  119.         Mat frame_HSV;
  120.         Mat frame_BLACK;
  121.         Mat frame_PINK;
  122.  
  123.  
  124.  
  125.         Mat storetransform;
  126.  
  127.         int start;
  128.         int finish;
  129.         while (frame.empty())
  130.             frame = captureFrame(); // Capture a frame from the camera and store in a new matrix variable
  131.         //imshow("Frame",frame);
  132.  
  133.         cvtColor(frame, frame_HSV, COLOR_BGR2HSV);
  134.         inRange(frame_HSV, Scalar(128, 25, 15), Scalar(179, 255, 255), frame_PINK);//Detects pink from the symbol and stores it in another matrix frame_PINK
  135.         //HSV values are set as variables here for different line colours
  136.         inRange(frame_HSV, Scalar(Hlow, Slow, Vlow), Scalar(Hhigh, Shigh, Vhigh), frame_BLACK);//Detects black line and stores it in matrix frame_BLACK
  137.         inRange(frame_HSV, Scalar(0, 0, 0), Scalar(180, 0, 0), comparator);
  138.  
  139.         //Crops the frames
  140.         frame_BLACK=frame_BLACK(Rect(0,0,320,20));
  141.         frame_PINK=frame_PINK(Rect(0,0,320,160));
  142.         comparator=comparator(Rect(0,0,320,160));
  143.         linecomparator=comparator(Rect(0,0,320,20));
  144.  
  145.         Mat spotFilter = cv::getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
  146.         cv::erode(comparator, comparator, spotFilter);
  147.  
  148.         pinkcompare=compareImages(comparator,frame_PINK);
  149.  
  150.         // checks if there is enough pink in the symbol frame to run Symbol detection
  151.         if(pinkcompare<75)//edit value
  152.         {
  153.             // Stop the car
  154.             // send data via I2C
  155.             I2C(0,0,servoangle);
  156.  
  157.             cout<<"Stopped to detect the symbol"<<endl;
  158.  
  159.             vector<vector<Point>> contours;
  160.             vector<Vec4i> hierarchy;
  161.  
  162.             findContours(frame_PINK, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0)); // Calculate the contours and store them
  163.  
  164.             vector<vector<Point>> approxedcontours(contours.size());
  165.  
  166.             for (int i = 0; i < contours.size(); i++)
  167.             {
  168.                 approxPolyDP(contours[i], approxedcontours[i], 10, true);
  169.                 //drawContours(frame, approxedcontours, (int)i, Scalar(255, 0, 0), 2, LINE_8, noArray(), 0, Point());
  170.  
  171.                 if (approxedcontours[i].size()==4)
  172.                 {
  173.                     Mat transformed = transformPerspective(approxedcontours[0], frame_PINK, 320, 240);
  174.  
  175.                     if(!transformed.empty())
  176.                     {
  177.                         cout<<"Hi"<<endl;
  178.                         //imshow("Transformed",transformed);
  179.                         rotate(transformed,transformed,ROTATE_180);
  180.                         Mat maskMorph = cv::getStructuringElement(MORPH_RECT, Size(10, 10));
  181.                         cv::dilate(transformed, transformed, maskMorph);
  182.                         storetransform=transformed;
  183.                         cout<<"Stored transformed"<<endl;
  184.                     }
  185.                 }
  186.  
  187.             }
  188.             float match = compareImages(storetransform,triangle);
  189.             float match1= compareImages(storetransform,circle);
  190.             float match2=compareImages(storetransform,star);
  191.             float match3=compareImages(storetransform,umbrella);
  192.             //imshow("Triangle",triangle);
  193.  
  194.             if((match1<match)&&(match>5)&&(match2<match)&&(match3<match))
  195.             {
  196.                 //Changes HSV values in frame_BLACK to detect a different coloured line based on Symbol detected
  197.                 cout<<"Triangle"<<endl;
  198.                 Hlow=96;
  199.                 Hhigh=115;
  200.                 Slow=142;
  201.                 Shigh=255;
  202.                 Vlow=23;
  203.                 Vhigh=255;
  204.                 cout<<"Following Blue"<<endl;
  205.                 /*for(int i=0;i<10001;i++)
  206.                 {
  207.                     cout<<i<<endl;
  208.  
  209.                 }*/
  210.                 //sleep(5);
  211.             }
  212.             else if((match1>match)&&(match1>5)&&(match2<match1)&&(match3<match1))
  213.             {
  214.                 cout<<"Circle"<<endl;
  215.                 Hlow=169;
  216.                 Hhigh=179;
  217.                 Slow=0;
  218.                 Shigh=255;
  219.                 Vlow=0;
  220.                 Vhigh=255;
  221.  
  222.             }
  223.             else if((match2>5)&&(match2>match1)&&(match2>match)&&(match3<match2))
  224.             {
  225.                 cout<<"Star"<<endl;
  226.                 Hlow=75;
  227.                 Hhigh=81;
  228.                 Slow=193;
  229.                 Shigh=255;
  230.                 Vlow=74;
  231.                 Vhigh=255;
  232.             }
  233.             else if((match3>5)&&(match3>match1)&&(match3>match)&&(match2<match3))
  234.             {
  235.                 cout<<"umbrella"<<endl;//values for yellow still need to be edited
  236.                 Hlow=128;
  237.                 Hhigh=179;
  238.                 Slow=0;
  239.                 Shigh=255;
  240.                 Vlow=0;
  241.                 Vhigh=130;
  242.             }
  243.             else if((match1<5)&&(match<5)&&(match2<5)&&(match3<5))
  244.             {
  245.                 cout<<"No shape detected"<<endl;
  246.             }
  247.             //  currentTime = clock();
  248.         }
  249.         /*if(pinkcompare>75)
  250.         pinkcompare=20;*/
  251.         do
  252.         {
  253.  
  254.  
  255.             bool intial=true; //Bool flag
  256.             //First bit of for loop taken from manual to read a row
  257.             uchar* p = frame_BLACK.ptr<uchar>(20);
  258.             for(int x = 0; x <frame_BLACK.cols; x++)
  259.             {
  260.  
  261.                 p[x]; // This is our B&W pixel data we can read it or write it
  262.                 uchar pixel = p[x]; // read the data into pixel
  263.                 if(pixel==255)
  264.                 {
  265.                     if(intial)
  266.                     {
  267.                         start=x; //Stores the intial pixel number that reads the white line each time a while loop is run
  268.                         intial=false;
  269.                     }
  270.                     finish=x; // Stores the final pixel number all the way on the right that reads the line each time the while loop is run
  271.                 }
  272.                 else
  273.                 {
  274.                     //cout<<" 0 ";
  275.                 }
  276.             }
  277.             int center = (start + finish) / 2;
  278.             int deviation = center - (frame_BLACK.cols / 2); // Calculate deviation from the center of the frame
  279.             float controlSignal = static_cast<double>(deviation) / (frame_BLACK.cols / 2); // Normalize deviation
  280.  
  281.             previouserror=error;
  282.             error=0.005-controlSignal;
  283.             totalerror=totalerror+error;
  284.  
  285.             u=(kp*error);
  286.             servoangle=centreangle+u;
  287.  
  288.             //send data via I2C
  289.             cout<<"Servo angle: "<<servoangle<<endl;
  290.  
  291.             I2C(90,90,servoangle);
  292.             linecompare=compareImages(linecomparator,frame_BLACK);
  293.             printf("Line compare \t: %f",linecompare);
  294.            
  295.             // If the line no longer appears in the line following frame it means it is no longer present so Pi switches back to following black
  296.             if(linecompare==100)
  297.             {
  298.  
  299.                 cout<<"Lost the line- switching to black"<<endl;
  300.                 Hlow=0;
  301.                 Hhigh=180;
  302.                 Slow=0;
  303.                 Shigh=102;
  304.                 Vlow=0;
  305.                 Vhigh=64;
  306.  
  307.             }
  308.  
  309.         }
  310.         while(linecompare<20);// Continuously runs line following while a line is present in the frame
  311.  
  312.         imshow("Linefollow",frame_BLACK);
  313.         imshow("Symbol detection",frame_PINK);
  314.  
  315.  
  316.  
  317.  
  318.         int key = waitKey(1); // Wait 1ms for a keypress (required to update windows)
  319.  
  320.         key = (key == 255) ? -1 : key; // Check if the ESC key has been pressed
  321.         if (key == 27)
  322.             break;
  323.     }
  324.  
  325.     closeCV(); // Disable the camera and close any windows
  326.  
  327.     return 0;
  328. }
  329.  
  330.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement