diff --git a/bin/RedBallDetection b/bin/RedBallDetection
index 7999779..cae72c4 100755
Binary files a/bin/RedBallDetection and b/bin/RedBallDetection differ
diff --git a/bin/RedBallTracking b/bin/RedBallTracking
new file mode 100755
index 0000000..5e08137
Binary files /dev/null and b/bin/RedBallTracking differ
diff --git a/color_params_RGB.xml b/color_params_RGB.xml
new file mode 100644
index 0000000..7765fb5
--- /dev/null
+++ b/color_params_RGB.xml
@@ -0,0 +1,9 @@
+
+
+25
+152
+64
+237
+220
+255
+
diff --git a/lib/RedBallDetection.o b/lib/RedBallDetection.o
index 1fdfd1d..7ebbe51 100644
Binary files a/lib/RedBallDetection.o and b/lib/RedBallDetection.o differ
diff --git a/lib/RedBallTracking.o b/lib/RedBallTracking.o
new file mode 100644
index 0000000..05e12f8
Binary files /dev/null and b/lib/RedBallTracking.o differ
diff --git a/makefile b/makefile
index 5e7bab4..4790545 100644
--- a/makefile
+++ b/makefile
@@ -1,6 +1,7 @@
-all: ReadWrite MonoCamCalib RedBallDetection
+all: ReadWrite MonoCamCalib RedBallDetection RedBallTracking
g++ lib/MonoCameraCalibration.o lib/ReadWriteFunctions.o -o bin/MonoCameraCalibration -L/usr/lib/x86_64-linux-gnu `pkg-config --libs opencv4`
g++ lib/RedBallDetection.o -o bin/RedBallDetection -L/usr/lib/x86_64-linux-gnu `pkg-config --libs opencv4`
+ g++ lib/RedBallTracking.o -o bin/RedBallTracking -L/usr/lib/x86_64-linux-gnu `pkg-config --libs opencv4`
MonoCamCalib: src/MonoCameraCalibration.cpp
g++ -c src/MonoCameraCalibration.cpp -o lib/MonoCameraCalibration.o -I./include -I/usr/include/opencv4
@@ -11,6 +12,8 @@ ReadWrite: src/ReadWriteFunctions.cpp
RedBallDetection: src/RedBallDetection.cpp
g++ -c src/RedBallDetection.cpp -o lib/RedBallDetection.o -I./include -I/usr/include/opencv4
+RedBallTracking: src/RedBallTracking.cpp
+ g++ -c src/RedBallTracking.cpp -o lib/RedBallTracking.o -I./include -I/usr/include/opencv4
clean:
rm lib/*.o
diff --git a/src/RedBallDetection.cpp b/src/RedBallDetection.cpp
index 6567c99..c898940 100644
--- a/src/RedBallDetection.cpp
+++ b/src/RedBallDetection.cpp
@@ -30,7 +30,8 @@ bool readCameraParameters(std::string filename, cv::Mat &camMatrix, cv::Mat & di
return true;
}
-bool writeColorParameters(std::string filename, int iLowH, int iHighH, int iLowS, int iHighS, int iLowV, int iHighV)
+//bool writeColorParameters(std::string filename, int iLowH, int iHighH, int iLowS, int iHighS, int iLowV, int iHighV)
+bool writeColorParameters(std::string filename, int iLowR, int iHighR, int iLowG, int iHighG, int iLowB, int iHighB)
{
cv::FileStorage fs(filename, cv::FileStorage::WRITE);
if (!fs.isOpened())
@@ -38,6 +39,9 @@ bool writeColorParameters(std::string filename, int iLowH, int iHighH, int iLowS
std::cout << "[ERROR] Could not open the file storage: " << filename << " !"<< std::endl;
return false;
}
+
+ /*
+
fs << "lowH" << iLowH;
fs << "highH" << iHighH;
@@ -47,6 +51,17 @@ bool writeColorParameters(std::string filename, int iLowH, int iHighH, int iLowS
fs << "lowV" << iLowV;
fs << "highV" << iHighV;
+ */
+
+ fs << "lowR" << iLowR;
+ fs << "highR" << iHighR;
+
+ fs << "lowG" << iLowG;
+ fs << "highG" << iHighG;
+
+ fs << "lowB" << iLowB;
+ fs << "highB" << iHighB;
+
// releases the writer
fs.release();
@@ -57,7 +72,8 @@ int main(int argc, char** argv)
{
// initializes main parameters
std::string sCameraParamFilename = CAM_PARAMS_FILENAME;
- std::string sColorParamFilename = COLOR_PARAMS_FILENAME;
+ //std::string sColorParamFilename = COLOR_PARAMS_FILENAME;
+ std::string sColorParamFilename = "color_params_RGB.xml";
int iStructuralElementSize = STRUCTURAL_ELEMENTS_SIZE;
float fFPS = FPS;
int iMaxVideoResolution = RESOLUTION_MAX;
@@ -125,6 +141,7 @@ int main(int argc, char** argv)
cv::namedWindow("Control", cv::WINDOW_AUTOSIZE); //create a window called "Control"
// sets min/max value for HSV color representation
+ /*
int iLowH = 0;
int iHighH = 179;
@@ -133,7 +150,16 @@ int main(int argc, char** argv)
int iLowV = 0;
int iHighV = 255;
+ */
+ int iLowR = 0;
+ int iHighR = 255;
+ int iLowG = 0;
+ int iHighG = 255;
+
+ int iLowB = 0;
+ int iHighB = 255;
+/*
// creates trackbars in "Control" window
cv::createTrackbar("LowH", "Control", &iLowH, 179); //Hue (0 - 179)
cv::createTrackbar("HighH", "Control", &iHighH, 179);
@@ -143,6 +169,18 @@ int main(int argc, char** argv)
cv::createTrackbar("LowV", "Control", &iLowV, 255); //Value (0 - 255)
cv::createTrackbar("HighV", "Control", &iHighV, 255);
+ */
+ // creates trackbars in "Control" window
+ cv::createTrackbar("LowR", "Control", &iLowR, 255); //Red (0 - 255)
+ cv::createTrackbar("HighR", "Control", &iHighR, 255);
+
+ cv::createTrackbar("LowG", "Control", &iLowG, 255); //Green (0 - 255)
+ cv::createTrackbar("HighG", "Control", &iHighG, 255);
+
+ cv::createTrackbar("LowB", "Control", &iLowB, 255); //Blue (0 - 255)
+ cv::createTrackbar("HighB", "Control", &iHighB, 255);
+
+
while (true)
{
@@ -168,7 +206,8 @@ int main(int argc, char** argv)
//Threshold the image based on the trackbar values
cv::Mat imgThresholded;
- inRange(imgHSV, cv::Scalar(iLowH, iLowS, iLowV), cv::Scalar(iHighH, iHighS, iHighV), imgThresholded);
+ //inRange(imgHSV, cv::Scalar(iLowH, iLowS, iLowV), cv::Scalar(iHighH, iHighS, iHighV), imgThresholded);
+ inRange(imgOriginal, cv::Scalar(iLowR, iLowG, iLowB), cv::Scalar(iHighR, iHighG, iHighB), imgThresholded);
//morphological opening (remove small objects from the foreground)
cv::erode(imgThresholded, imgThresholded, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(iStructuralElementSize, iStructuralElementSize)) );
@@ -197,7 +236,8 @@ int main(int argc, char** argv)
}
if (key == 's')
{
- writeColorParameters(sColorParamFilename, iLowH, iHighH, iLowS, iHighS, iLowV, iHighV);
+ //writeColorParameters(sColorParamFilename, iLowH, iHighH, iLowS, iHighS, iLowV, iHighV);
+ writeColorParameters(sColorParamFilename, iLowR, iHighR, iLowG, iHighG, iLowB, iHighB);
std::cout << "[INFO] Color parameters saved to file: " << sColorParamFilename << std::endl;
}
diff --git a/src/RedBallTracking.cpp b/src/RedBallTracking.cpp
new file mode 100644
index 0000000..7ab68ab
--- /dev/null
+++ b/src/RedBallTracking.cpp
@@ -0,0 +1,235 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
+#include
+
+#define CAM_PARAMS_FILENAME "./data/camera_calibration_params.xml"
+#define COLOR_PARAMS_FILENAME "./data/color_params.xml"
+#define FPS 30.0
+#define STRUCTURAL_ELEMENTS_SIZE 5
+#define AREA_THRESOLD 1000
+#define RESOLUTION_MAX 800
+
+using namespace cv;
+using namespace std;
+
+bool readCameraParameters(std::string filename, cv::Mat &camMatrix, cv::Mat & distCoeffs)
+{
+ cv::FileStorage fs(filename, cv::FileStorage::READ);
+ if (!fs.isOpened())
+ {
+ std::cout << "[ERROR] Could not open the camera parameter file storage: " << filename << " !"<< std::endl;
+ return false;
+ }
+
+ fs["camera_matrix"] >> camMatrix;
+ fs["distortion_coefficients"] >> distCoeffs;
+
+ return true;
+}
+
+bool readColorParameters(std::string filename, int& iLowH, int& iHighH, int& iLowS, int& iHighS, int& iLowV, int& iHighV)
+{
+ cv::FileStorage fs(filename, cv::FileStorage::READ);
+ if (!fs.isOpened())
+ {
+ std::cout << "[ERROR] Could not open the color paramter file storage: " << filename << " !"<< std::endl;
+ return false;
+ }
+
+ fs["lowH"] >> iLowH;
+ fs["highH"] >> iHighH;
+
+ fs["lowS"] >> iLowS;
+ fs["highS"] >> iHighS;
+
+ fs["lowV"] >> iLowV;
+ fs["highV"] >> iHighV;
+
+ return true;
+}
+
+ int main( int argc, char** argv )
+ {
+ // initializes main parameters
+ std::string sCameraParamFilename = CAM_PARAMS_FILENAME;
+ std::string sColorParamFilename = COLOR_PARAMS_FILENAME;
+ float fFPS = FPS;
+ int iStructuralElementSize = STRUCTURAL_ELEMENTS_SIZE;
+ int iAreaThresold = AREA_THRESOLD;
+ int iMaxVideoResolution = RESOLUTION_MAX;
+
+ // updates main parameters from arguments
+ int opt;
+ while ((opt = getopt (argc, argv, ":c:f:s:a:i:r:")) != -1)
+ {
+ switch (opt)
+ {
+ case 'c':
+ sColorParamFilename = optarg;
+ break;
+ case 'f':
+ fFPS = atof(optarg);
+ break;
+ case 's':
+ iStructuralElementSize = atoi(optarg);
+ break;
+ case 'a':
+ iAreaThresold = atoi(optarg);
+ break;
+ case 'i':
+ sCameraParamFilename = optarg;
+ break;
+ case 'r':
+ iMaxVideoResolution = atoi(optarg);
+ break;
+ case '?':
+ if (optopt == 'c' || optopt == 'f' || optopt == 's' || optopt == 'a' | optopt == 'r')
+ fprintf (stderr, "Option -%c requires an argument.\n", optopt);
+ else if (isprint (optopt))
+ fprintf (stderr, "Unknown option `-%c'.\n", optopt);
+ else
+ fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
+ return 1;
+ default:
+ abort ();
+ }
+ }
+
+ // reads color parameters from the file storage
+ int iLowH, iHighH, iLowS, iHighS, iLowV, iHighV;
+ bool isColorParamsSet = readColorParameters(sColorParamFilename, iLowH, iHighH, iLowS, iHighS, iLowV, iHighV);
+
+ // checks if the color parameters were successfully read
+ if (!isColorParamsSet)
+ {
+ std::cout << "[ERROR] Color parameters could not be loaded!" << std::endl;
+ return -1;
+ }
+
+ // distorted/undistorted image
+ bool bIsImageUndistorted = true;
+
+ // reads camera intrinsic parameters
+ cv::Mat cameraMatrix, distCoeffs;
+ bool isCamParamsSet = readCameraParameters(sCameraParamFilename, cameraMatrix, distCoeffs);
+
+ // checks if the camera parameters were successfully read
+ if (!isCamParamsSet)
+ {
+ std::cout << "[WARNING] Camera intrinsic parameters could not be loaded!" << std::endl;
+ }
+
+ // creates a camera grabber
+ VideoCapture cap(0, cv::CAP_V4L2); //capture the video from webcam
+
+ // changes image resolution to maximum (e.g. 1920x1080 if possible)
+ cap.set(cv::CAP_PROP_FRAME_HEIGHT, iMaxVideoResolution); cap.set(cv::CAP_PROP_FRAME_WIDTH, iMaxVideoResolution);
+
+ // checks if the camera was successfully opened
+ if ( !cap.isOpened() ) // if not success, exit program
+ {
+ cout << "[ERROR] Could not open the camera!" << endl;
+ return -1;
+ }
+
+ // inits previous x,y location of the ball
+ int iLastX = -1;
+ int iLastY = -1;
+
+ // captures a temporary image from the camera
+ Mat imgTmp;
+ cap.read(imgTmp);
+
+ // creates a black image with the size as the camera output
+ Mat imgLines = Mat::zeros( imgTmp.size(), CV_8UC3 );
+
+ // main loop launched every FPS
+ while (true)
+ {
+ // reads a new frame from video
+ cv::Mat imgOriginal;
+ bool bSuccess = cap.read(imgOriginal);
+
+ // checks if a new frame was grabbed
+ if (!bSuccess) //if not success, break loop
+ {
+ std::cout << "[WARNING] Could not read a new frame from video stream" << std::endl;
+ break;
+ }
+
+ if (bIsImageUndistorted && isCamParamsSet)
+ {
+ cv::Mat temp = imgOriginal.clone();
+ cv::undistort(temp, imgOriginal, cameraMatrix, distCoeffs);
+ }
+
+ // converts the captured frame from BGR to HSV
+ cv::Mat imgHSV;
+ cvtColor(imgOriginal, imgHSV, cv::COLOR_BGR2HSV);
+
+ // thresholds the image based on the trackbar values
+ cv::Mat imgThresholded;
+ inRange(imgHSV, cv::Scalar(iLowH, iLowS, iLowV), cv::Scalar(iHighH, iHighS, iHighV), imgThresholded);
+
+ // applies morphological opening (removes small objects from the foreground)
+ cv::erode(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(iStructuralElementSize, iStructuralElementSize)) );
+ cv::dilate( imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(iStructuralElementSize, iStructuralElementSize)) );
+
+ // applies morphological closing (removes small holes from the foreground)
+ cv::dilate( imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(iStructuralElementSize, iStructuralElementSize)) );
+ cv::erode(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(iStructuralElementSize, iStructuralElementSize)) );
+
+ // calculates the moments of the thresholded image
+ Moments oMoments = moments(imgThresholded);
+ double dM01 = oMoments.m01;
+ double dM10 = oMoments.m10;
+ double dArea = oMoments.m00;
+
+ // if the area <= iAreaThresold, considers that the there are no object in the image and it's because of the noise, the area is not zero
+ if (dArea > iAreaThresold)
+ {
+ // calculates the position of the ball
+ int posX = dM10 / dArea;
+ int posY = dM01 / dArea;
+
+ if (iLastX >= 0 && iLastY >= 0 && posX >= 0 && posY >= 0)
+ {
+ // draww a red line from the previous point to the current point
+ line(imgLines, Point(posX, posY), Point(iLastX, iLastY), Scalar(0,0,255), 2);
+ }
+
+ // stores the current position for enxt frame
+ iLastX = posX;
+ iLastY = posY;
+ }
+
+ // displays the thresholded image
+ imshow("Thresholded Image", imgThresholded);
+
+ // shows the original image with the tracking (red) lines
+ imgOriginal = imgOriginal + imgLines;
+ imshow("Original", imgOriginal);
+
+ // waits for awhile depending on the FPS value
+ char key = (char)cv::waitKey(1000.0/fFPS);
+ // checks if ESC was pressed to exit
+ if (key == 27) // if 'esc' key is pressed, break loop
+ {
+ std::cout << "[INFO] esc key is pressed by user -> Shuting down!" << std::endl;
+ break;
+ }
+ if (key == 'u')
+ {
+ bIsImageUndistorted = !bIsImageUndistorted;
+ std::cout << "[INFO] Image undistorted: " << bIsImageUndistorted<< std::endl;
+ }
+ }
+
+ return 0;
+}
\ No newline at end of file