Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

opencv videocapture lag

hi everybody,

we have implemented a colour detection, as can be seen in the attached code. the problem is, that when moving the object, that shall be detected, reveils a delay of about 3 seconds. we assume the problem is the buffer size of the processed frames is too big.

a solution might be to process only every n-th frame, instead of each. unfortunately I can't access the lab these days, so if someone has further ideas I'm very thankful for every input.

#include <cv.h>
#include <highgui.h>
#include <iostream>
#include "opencv2/imgproc/imgproc.hpp"
#include <math.h>

using namespace cv;

//initial min and max HSV filter values.
//these will be changed using trackbars
int H_MIN = 167;
int H_MAX = 195;
int S_MIN = 121;
int S_MAX = 256;
int V_MIN = 0;
int V_MAX = 256;


//default capture width and height
const int FRAME_WIDTH = 640;
const int FRAME_HEIGHT = 480;
//max number of objects to be detected in frame
const int MAX_NUM_OBJECTS=50;
//minimum and maximum object area
const int MIN_OBJECT_AREA = 5*5;
const int MAX_OBJECT_AREA = FRAME_HEIGHT*FRAME_WIDTH/1.5;
//names that will appear at the top of each window
const string windowName = "Original Image";
const string windowName1 = "HSV Image";
const string windowName2 = "Thresholded Image";
const string windowName3 = "After Morphological Operations";
const string trackbarWindowName = "Trackbars";



// Marker Jump
#define  ArraySize 5
int CoordinatesHistory[ArraySize][2];
int CurrentCoordinates[1][2];

int distance = 0;
int radius = 0;
int history = 0;


void on_trackbar( int, void* )
{//This function gets called whenever a
    // trackbar position is changed

}

string intToString(int number){
    std::stringstream ss;
    ss << number;
    return ss.str();
}
void createTrackbars(){
    //create window for trackbars
     createTrackbar( "H_MIN", trackbarWindowName, &H_MIN, H_MAX, on_trackbar );
    createTrackbar( "H_MAX", trackbarWindowName, &H_MAX, H_MAX, on_trackbar );
    createTrackbar( "S_MIN", trackbarWindowName, &S_MIN, S_MAX, on_trackbar );
    createTrackbar( "S_MAX", trackbarWindowName, &S_MAX, S_MAX, on_trackbar );
    createTrackbar( "V_MIN", trackbarWindowName, &V_MIN, V_MAX, on_trackbar );
    createTrackbar( "V_MAX", trackbarWindowName, &V_MAX, V_MAX, on_trackbar );
 }
void drawObject(int x, int y,Mat &frame){

    //use some of the openCV drawing functions to draw crosshairs
    //on your tracked image!

    //UPDATE:JUNE 18TH, 2013
    //added 'if' and 'else' statements to prevent
    //memory errors from writing off the screen (ie. (-25,-25) is not within the window!)

    circle(frame,Point(x,y),20,Scalar(0,255,0),2);
    if(y-25>0)
    line(frame,Point(x,y),Point(x,y-25),Scalar(0,255,0),2);
    else line(frame,Point(x,y),Point(x,0),Scalar(0,255,0),2);
    if(y+25<FRAME_HEIGHT)
    line(frame,Point(x,y),Point(x,y+25),Scalar(0,255,0),2);
    else line(frame,Point(x,y),Point(x,FRAME_HEIGHT),Scalar(0,255,0),2);
    if(x-25>0)
    line(frame,Point(x,y),Point(x-25,y),Scalar(0,255,0),2);
    else line(frame,Point(x,y),Point(0,y),Scalar(0,255,0),2);
    if(x+25<FRAME_WIDTH)
    line(frame,Point(x,y),Point(x+25,y),Scalar(0,255,0),2);
    else line(frame,Point(x,y),Point(FRAME_WIDTH,y),Scalar(0,255,0),2);

    putText(frame,intToString(x)+","+intToString(y),Point(x,y+30),1,1,Scalar(0,255,0),2);

}
void morphOps(Mat &thresh){

    //create structuring element that will be used to "dilate" and "erode" image.
    //the element chosen here is a 3px by 3px rectangle

    Mat erodeElement = getStructuringElement( MORPH_RECT,Size(3,3));
    //dilate with larger element so make sure object is nicely visible
    Mat dilateElement = getStructuringElement( MORPH_RECT,Size(8,8));

    erode(thresh,thresh,erodeElement);
    erode(thresh,thresh,erodeElement);


    dilate(thresh,thresh,dilateElement);
    dilate(thresh,thresh,dilateElement);
 }

void trackFilteredObject(int &x, int &y, Mat &threshold, Mat &cameraFeed)
{
    vector< vector<Point> > contours;
    vector<Vec4i> hierarchy;
    Mat temp;
    threshold.copyTo(temp);
    double diameter;

    // find external contours ignores holes
        cv::findContours(temp, contours, hierarchy, CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);
        //if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
    if (contours.size() > MAX_NUM_OBJECTS)
    {
        putText(cameraFeed, "TOO MUCH NOISE! ADJUST FILTER", Point(0, 50), 1, 2, Scalar(0, 0, 255), 2);
        return;
    }

     double refArea = 0;
    bool objectFound = false;
    //int largest = -1;

    for (size_t i = 0; i < contours.size(); i++)
    {
        cv::Moments moment = moments(contours[i]);
        double area = moment.m00;
        double perimeter = cv::arcLength(contours[i], true);
        diameter = perimeter/(M_PI);
        int cx = cvRound(moment.m10 / area);
        int cy = cvRound(moment.m01 / area);

        if (  area > refArea && area > MIN_OBJECT_AREA && area < MAX_OBJECT_AREA )
            {
                 cv::Point center(cx, cy);
                    int radius = cvRound(sqrt(area / CV_PI));

                    // circle center
                    circle(cameraFeed, center, 3, Scalar(0, 255, 0), -1, 8, 0);
                    // circle outline
                    circle(cameraFeed, center, radius, Scalar(255, 0, 0), 3, 8, 0);

                    // DRAW GREEN CROSS
                    drawObject(cx, cy, cameraFeed);
                    objectFound = true;
                    x = cx;
                    y = cy;
                    refArea = area;
        }
        else
        {
                objectFound = false;
                x = -1;
                y = -1;
        }
    }
    //let user know you found an object
    if (objectFound == true)
    {
        //std::cout << "Object Found" << std::endl;
        putText(cameraFeed, "Tracking Object", Point(0, 50), 2, 1, Scalar(0, 255, 0), 2);
   }
}

int main(int argc, char* argv[])
{
     //some boolean variables for different functionality within this
    //program
    bool trackObjects = true;
    bool useMorphOps = true;
    //Matrix to store each frame of the webcam feed
    Mat cameraFeed;
    //matrix storage for HSV image
    Mat HSV;
    //matrix storage for binary threshold image
    Mat threshold;
    //x and y values for the location of the object
    int x=-1, y=-1;
    //create slider bars for HSV filtering
    createTrackbars();

    //open capture object at location zero (default location for webcam)
    VideoCapture capture(0);//
    capture.open(0);// open the video file for reading
    //set height and width of capture frame
    capture.set(CV_CAP_PROP_FRAME_WIDTH,FRAME_WIDTH);
    capture.set(CV_CAP_PROP_FRAME_HEIGHT,FRAME_HEIGHT);
    //start an infinite loop where webcam feed is copied to cameraFeed matrix
    //all of our operations will be performed within this loop
    while(1){

        auto Start_Time = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
        //store image to matrix
        capture.read(cameraFeed);
        //convert frame from BGR to HSV colorspace
        cvtColor(cameraFeed,HSV,COLOR_RGB2HSV);
        capture.

        //filter HSV image between values and store filtered image to
        //threshold matrix
        inRange(HSV,Scalar(H_MIN,S_MIN,V_MIN),Scalar(H_MAX,S_MAX,V_MAX),threshold);
        //perform morphological operations on thresholded image to eliminate noise
        //and emphasize the filtered object(s)

        if(useMorphOps)
        morphOps(threshold);

        for ( int j = ArraySize-1; j < 0;j--)
               {
                    CoordinatesHistory[j][0]=CoordinatesHistory[j-1][0];
                    CoordinatesHistory[j][1]=CoordinatesHistory[j-1][1];
               }
               CoordinatesHistory[0][0]=x;
               CoordinatesHistory[0][1]=y;

               distance = sqrt(pow(x-CoordinatesHistory[history][0],2)+pow(y-CoordinatesHistory[history][1],2));
               if (distance >= radius)
               {
                   x = -1;
                   y = -1;
               }

  vector<Vec3f> circles;

        //pass in thresholded frame to our object tracking function
        //this function will return the x and y coordinates of the
        //filtered object
        if(trackObjects)
            trackFilteredObject(x,y,threshold,cameraFeed);

       if (x > 0 && y > 0)
       {
        Vec3b hsv=HSV.at<Vec3b>(y,x);

        int H = hsv.val[0];
        int S = hsv.val[1];
        int V = hsv.val[2];

         std::cout << "H:  " << H << std::endl;
         std::cout << "S:  " << S << std::endl;
         std::cout << "V:  " << V << std::endl;
       }

        // Functionalty: Check for "Marker-Jumps"
        for ( int j = ArraySize-1; j < 0;j--)
            {
                CoordinatesHistory[j][0]=CoordinatesHistory[j-1][0];
                CoordinatesHistory[j][1]=CoordinatesHistory[j-1][1];
            }
            CoordinatesHistory[0][0]=x;
            CoordinatesHistory[0][1]=y;

        //show frames
        imshow(windowName2,threshold);
        imshow(windowName,cameraFeed);
        imshow(windowName1,HSV);

       //delay 30ms so that screen can refresh.
        //image will not appear without this waitKey() command
        waitKey(1);

        auto End_Time = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
        int Duration = End_Time-Start_Time;
        int Framerate = 1000/Duration;
        std::cout << "Duration:" << Duration << std::endl;
        std::cout << "Framerate:"<< Framerate << std::endl;
        std::cout << "Coordinates: "<< x <<"/" <<y << std::endl;
    }
   return 0;
}

best grisi