From 5b4769e8f0c2fec03d6de0fc7c7e40e982efe910 Mon Sep 17 00:00:00 2001 From: Balthazar Squinabol Date: Wed, 22 May 2024 15:15:08 +0200 Subject: [PATCH] color threshold --- bin/RedBallDetection | Bin 0 -> 39896 bytes data/color_params_data.xml | 9 ++ lib/RedBallDetection.o | Bin 0 -> 39680 bytes makefile | 10 +- src/RedBallDetection.cpp | 199 ++++++++++++++++++++++++++++++++ src/RedBallTracking.cpp | 227 +++++++++++++++++++++++++++++++++++++ 6 files changed, 441 insertions(+), 4 deletions(-) create mode 100755 bin/RedBallDetection create mode 100644 data/color_params_data.xml create mode 100644 lib/RedBallDetection.o create mode 100644 src/RedBallDetection.cpp create mode 100644 src/RedBallTracking.cpp diff --git a/bin/RedBallDetection b/bin/RedBallDetection new file mode 100755 index 0000000000000000000000000000000000000000..a253a1c8c2818d69f2c3567bcc71654975a39a0d GIT binary patch literal 39896 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 + +0 +179 +0 +219 +0 +255 + diff --git a/lib/RedBallDetection.o b/lib/RedBallDetection.o new file mode 100644 index 0000000000000000000000000000000000000000..b308650491bb3a9aa195020b50fd0c7cfa71b107 GIT binary patch literal 39680 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 +#include +#include +#include +#include + +#include +#include +#include + +#define CAM_PARAMS_FILENAME "./data/microsoft_livecam_hd3000.xml" +#define COLOR_PARAMS_FILENAME "./data/color_params_data.xml" +#define FPS 30.0 +#define STRUCTURAL_ELEMENTS_SIZE 5 + +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 writeColorParameters(std::string filename, int iLowH, int iHighH, int iLowS, int iHighS, int iLowV, int iHighV) +{ + cv::FileStorage fs(filename, cv::FileStorage::WRITE); + if (!fs.isOpened()) + { + std::cout << "[ERROR] Could not open the 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; + + // releases the writer + fs.release(); + + return true; +} + +int main(int argc, char** argv) +{ + // initializes main parameters + std::string sCameraParamFilename = CAM_PARAMS_FILENAME; + std::string sColorParamFilename = COLOR_PARAMS_FILENAME; + int iStructuralElementSize = STRUCTURAL_ELEMENTS_SIZE; + float fFPS = FPS; + + // updates main parameters from arguments + int opt; + while ((opt = getopt (argc, argv, ":i:f:o:s:")) != -1) + { + switch (opt) + { + case 'o': + sColorParamFilename = optarg; + break; + case 'f': + fFPS = atof(optarg); + break; + case 'i': + sCameraParamFilename = optarg; + break; + case 's': + iStructuralElementSize = atoi(optarg); + break; + case '?': + if (optopt == 'o' || optopt == 'f' || optopt == 'i' || optopt == 's') + 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 (); + } + } + + // 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 + cv::VideoCapture cap(0, cv::CAP_V4L2); + + // checks if the camera was successfully opened + if (!cap.isOpened()) + { + std::cout << "[ERROR] Cannot open the webcam" << std::endl; + return 1; + } + + 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; + + int iLowS = 0; + int iHighS = 255; + + int iLowV = 0; + int iHighV = 255; + + // creates trackbars in "Control" window + cv::createTrackbar("LowH", "Control", &iLowH, 179); //Hue (0 - 179) + cv::createTrackbar("HighH", "Control", &iHighH, 179); + + cv::createTrackbar("LowS", "Control", &iLowS, 255); //Saturation (0 - 255) + cv::createTrackbar("HighS", "Control", &iHighS, 255); + + cv::createTrackbar("LowV", "Control", &iLowV, 255); //Value (0 - 255) + cv::createTrackbar("HighV", "Control", &iHighV, 255); + + while (true) + { + cv::Mat imgOriginal; + + bool bSuccess = cap.read(imgOriginal); // read a new frame from video + + if (!bSuccess) //if not success, break loop + { + std::cout << "[WARNING] Cannot read a frame from video stream" << std::endl; + break; + } + + if (bIsImageUndistorted && isCamParamsSet) + { + cv::Mat temp = imgOriginal.clone(); + cv::undistort(temp, imgOriginal, cameraMatrix, distCoeffs); + } + + //Convert the captured frame from BGR to HSV + cv::Mat imgHSV; + cvtColor(imgOriginal, imgHSV, cv::COLOR_BGR2HSV); + + //Threshold the image based on the trackbar values + cv::Mat imgThresholded; + inRange(imgHSV, cv::Scalar(iLowH, iLowS, iLowV), cv::Scalar(iHighH, iHighS, iHighV), imgThresholded); + + //morphological opening (remove small objects from the foreground) + cv::erode(imgThresholded, imgThresholded, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(iStructuralElementSize, iStructuralElementSize)) ); + cv::dilate( imgThresholded, imgThresholded, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(iStructuralElementSize, iStructuralElementSize)) ); + + //morphological closing (fill small holes in the foreground) + cv::dilate( imgThresholded, imgThresholded, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(iStructuralElementSize, iStructuralElementSize)) ); + cv::erode(imgThresholded, imgThresholded, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(iStructuralElementSize, iStructuralElementSize)) ); + + cv::imshow("Thresholded Image", imgThresholded); //show the thresholded image + cv::imshow("Original", imgOriginal); //show the original image + + // waits for awhile depending on the FPS value + // checks if ESC was pressed to exit + char key = (char)cv::waitKey(1000.0/fFPS); + //wait for 'esc' key press for 30ms. If 'esc' key is pressed, break loop + if (key == 27) + { + 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; + } + if (key == 's') + { + writeColorParameters(sColorParamFilename, iLowH, iHighH, iLowS, iHighS, iLowV, iHighV); + std::cout << "[INFO] Color parameters saved to file: " << sColorParamFilename << std::endl; + } + + + } + + return 0; +} diff --git a/src/RedBallTracking.cpp b/src/RedBallTracking.cpp new file mode 100644 index 0000000..89f535f --- /dev/null +++ b/src/RedBallTracking.cpp @@ -0,0 +1,227 @@ +#include +#include +#include +#include +#include + +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include + +#define CAM_PARAMS_FILENAME "./data/microsoft_livecam_hd3000.xml" +#define COLOR_PARAMS_FILENAME "./data/color_params_data.xml" +#define FPS 30.0 +#define STRUCTURAL_ELEMENTS_SIZE 5 +#define AREA_THRESOLD 1000 + +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; + + // updates main parameters from arguments + int opt; + while ((opt = getopt (argc, argv, ":c:f:s:a:i:")) != -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 '?': + if (optopt == 'c' || optopt == 'f' || optopt == 's' || optopt == 'a') + 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 + + // 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