Ask Your Question
0

CPU Usage (optical flow)

asked 2017-01-15 10:27:16 -0600

alecs26 gravatar image

updated 2017-01-15 20:39:02 -0600

Tetragramm gravatar image

Hello,

I want to detect faces with OpenCV and apply an optical flow to follow the face. My code works but it is expensive for the CPU (the CPU runs at 20%).

I capture an image at with "capture >> frame" (which gives a new image at each 30ms). Running only this requires 5% of the CPU. However, if I add the code for optical flow "cv::calcOpticalFlowPyrLK(prevGray, gray, prevPoints, currPoints, status, err, winSize, 3, termcrit, 0, 0.001);", running the program leads to a constant CPU usage of 20% for the program. I would very much like to reduce this CPU usage even if my program takes more time to operate.

cv::setNumThreads(2) helps a lot (CPU 10%) but I would like to see other possible methods to optimize.

Here is the code I use (the feature points for the optical flow are pre-generated to simplify the code):

Thank you so much !

Alex

int main(int argc, char *argv[])
{
//cv::setNumThreads(2);

cv::Mat frame;
cv::Mat frametemp;
cv::Mat gray;
cv::Mat prevGray;
cv::vector<cv::Point2f> prevPoints;

cv::vector<uchar> status;
cv::vector<float> err;

cv::VideoCapture capture(0);

float landmarks[68][2];

while (true)
{
    capture >> frame;
    if (!frame.empty())
    {
        for (int i = 0; i < 68; i++)
        {
            landmarks[i][0] = i*5;
            landmarks[i][1] = i*5;
        }

            frame.copyTo(frametemp);
            cvtColor(frametemp, gray, cv::COLOR_BGR2GRAY);
            if (prevGray.empty())
            {
                gray.copyTo(prevGray);
            }

            cv::vector<cv::Point2f> currPoints;

            for (int k = 0; k < 68; k++)
            {
                currPoints.push_back(cv::Point2f(landmarks[k][0], landmarks[k][1]));
            }

            if (!prevPoints.empty())
            {
                cv::calcOpticalFlowPyrLK(prevGray, gray, prevPoints, currPoints, status, err, winSize, 3, termcrit, 0, 0.01);
            }

            std::swap(currPoints, prevPoints);
            cv::swap(prevGray, gray);
    }
    else
    {
        printf(" --(!) No captured frame -- Break!"); break;
    }
    //Sleep(3);
}

return 0;
}
edit retag flag offensive close merge delete

Comments

1

You could try running two threads, a capture thread that stores the camera images to a thread-safe buffer and an optical flow thread that reads images from the thread safe buffer and processes them. This may decrease latency and increase frame rate, but it won't reduce cpu usage and might even increase it. Another thing to try is reducing the image resolution. Many cameras capture at VGA, but it is often acceptable to perform all operations at QVGA. You can always up-res with guided filters to get results at VGA and still save on computation.

Der Luftmensch gravatar imageDer Luftmensch ( 2017-01-15 20:44:50 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
1

answered 2017-01-15 20:38:14 -0600

Tetragramm gravatar image

Well, cv::setNumThreads(1) would be even less than that, obviously. Fortunately, there is a simple method that can get you a middling to large portion of your CPU back without sacrificing time.

Inside calcOpticalFlowPyrLK is two calls to the buildOpticalFlowPyramid function. Since you're using the same frame twice, they pyramid for that frame is built twice. You can instead create the pyramid yourself once, and pass it in place of the images in the arguments.

Second, unless I'm missing something, you only use the values in landmarks once, for the first frame. Instead of creating them every frame and then dropping them, fill landmarks and currPoints once at the beginning.

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2017-01-15 10:27:16 -0600

Seen: 1,281 times

Last updated: Jan 15 '17