Ask Your Question
0

How to take average every X frames

asked 2016-11-10 11:55:50 -0600

DT0311 gravatar image

Hi, I want to take average of every 15 images

This is currently what I have:

int main() {
    VideoCapture cap(0); // open the default camera
    if (!cap.isOpened())  // check if we succeeded
        return -1;
    cap.set(CV_CAP_PROP_FPS, 15);

    std::vector<cv::Mat> images(9000);
    for (framenumb = 0; framenumb < 9000; ++framenumb)
    {
        Mat frame;
        cap >> frame;
        if (frame.empty()) break; // end of video stream
        if (waitKey(1) == 27) break; // stop capturing by pressing ESC 
        images[framenumb].create(480, 640, CV_8UC3);
        frame.copyTo(images[framenumb]);
        imshow("webcam", images[framenumb]);
    }
    for (int i = 0; i < 600; i++)
            {
                Mat avgImg(480, 640, CV_32FC3, Scalar());
                for (framenumb = 15 * i; framenumb < (15 * i) + 15; ++framenumb)
                {
                    cv::accumulate(images[framenumb], avgImg);
                }
                //stacking every 15 images into a single image
                avgImg = avgImg / 15;
                avgImg.convertTo(avgImg, CV_8UC3);
                char filename[80];
                sprintf(filename, "C:/AvgPics/test_%d.jpeg", framenumb);
                imwrite(filename, avgImg);

However, this will need me to create a vector of 9000 images, which is a bit excessive. Is there a way for me to accomplish this without having to use a vector?

edit retag flag offensive close merge delete

Comments

forget vector images

use an index i in loop framenumb to count frame from 0 to 14 and accumulate image (like you have already done)

LBerger gravatar imageLBerger ( 2016-11-10 14:10:09 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
1

answered 2016-11-10 23:27:59 -0600

berak gravatar image

updated 2016-11-10 23:40:27 -0600

you should not cache thousands of images in a vector to achieve this, rather use a (short) ringbuffer for the desired accumulation, and do it all online

c++ also has more containers than vector, we can use a std::deque here, and simply push the most recent image into one end, and pop the oldest image at the other end (fifo)

#include <opencv2/opencv.hpp>
#include <iostream>
#include <deque>

using namespace cv;
using namespace std;


int main()
{
    std::deque<cv::Mat> ring;

    VideoCapture cap(0); 
    if (!cap.isOpened())
        return -1;

    while(true)
    {
        Mat frame;
        cap >> frame;
        if (frame.empty()) break;

        ring.push_back(frame);
        if (ring.size() > 15) 
        {
            ring.pop_front();

            Mat avgImg(frame.size(), CV_32FC3, Scalar());
            for (int i=0; i<15; i++)
                accumulate(ring[i], avgImg);

            avgImg.convertTo(avgImg, CV_8UC3, 1.0/15);
            imshow("avg", avgImg);
        }

        imshow("webcam", frame);
        if (waitKey(10) > 0) break;
    }
    return EXIT_SUCCESS;
}
edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2016-11-10 11:55:50 -0600

Seen: 3,438 times

Last updated: Nov 10 '16