简体   繁体   中英

OpenCV histogram doesn't update, despite new video data

I'm trying to compute a histogram for each frame coming in from a single-channel black and white video stream. Eventually, I'll be feeding back projections of these histograms to OpenCV's camshift function.

Here's my code:

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main(int argc, char* argv[]) {

    Mat frame, back, fore, hist, image, v_hist;
    BackgroundSubtractorMOG2 bgs;
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    int bins = 8; 
    int histSize[] = { bins };
    float range[] = { 0, 255 }; //values will range from 0 to 256
    const float* histRange = { range };
    bool uniform = true, accumulate = true;

    VideoCapture cap(0);
    if (!cap.isOpened()) {
        cout << "Cannot open the video cam" << endl;
        return -1;
    }

    namedWindow("histogram",CV_WINDOW_AUTOSIZE);
    namedWindow("Foreground",CV_WINDOW_AUTOSIZE);

    for (;;) {
        if (!cap.read(frame)){
            cout << "No frame" << endl;
            break;
        }

        frame.copyTo(image);

        //***start mask computation***
        bgs.operator()(image, fore);
        bgs.getBackgroundImage(back);

        findContours(fore, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

        int idx = 0;
        for( ; idx >= 0; idx = hierarchy[idx][0] ){
            Scalar color( 255, 255, 255 );
            drawContours( fore, contours, idx, color, CV_FILLED, 8, hierarchy );
        }

        erode(fore, fore, Mat());
        erode(fore, fore, Mat());
        dilate(fore, fore, Mat());
        dilate(fore, fore, Mat());
        //****end mask computation****

        calcHist( &fore, 1, 0, Mat(), v_hist, 1, histSize, &histRange, uniform, accumulate);

        int hist_w = 512; int hist_h = 400;
        int bin_w = cvRound( (double) hist_w/ (*histSize) );

        Mat histImage( hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0) );

        normalize( v_hist, v_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );

        //draw histogram
        for (int i = 1; i < *histSize; i++)
            line ( histImage, 
            Point(bin_w*(i-1), hist_h - cvRound(v_hist.at<float>(i-1)) ),
            Point( bin_w*(i), hist_h - cvRound(v_hist.at<float>(i)) ),
            Scalar( 255, 255, 255), 2, 8, 0  );

        if(!histImage.empty()) imshow("histogram", histImage);

        if(!fore.empty()) imshow("Foreground", fore);


        if (waitKey(30) >= 0) break;

    }
    return 0;
}

This is what the output initially looks like (bear in mind - at the outset, the foreground mask is all black): 初始蒙版和直方图

..but even after foreground extraction, the histogram remains unchanged: 稍后,前景遮罩和直方图

It seems like this histogram applies to the first, all-black image only, which is why the line goes to y=0 starting at x=(length of x-axis)/8. This makes sense, because the histogram has 8 bins and all of the values in this original picture are 0. (FWIW: when there are only 2 bins, the line goes to y=0 starting at x=(length of x-axis)/2.)

I've drawn lines and rectangles with OpenCV in the past, and haven't ever had to do much different from what I'm doing here, so I'm reasonably certain that this isn't an issue with any of the drawing functions. If that's the case, it seems like the histogram isn't updating as new video data comes in.

Does anybody have an idea as to why this might be happening?

While I haven't found out exactly why the drawn histogram isn't updating, I've done some testing and now feel confident that the histograms are changing between different frames.

Here's the code I've added to my previous program:

//new declarations
Mat last_hist;
bool first = true;

//code is the same, leading up to...
normalize( v_hist, v_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );

if (!first){
    eq = std::equal( v_hist.begin<uchar>(), v_hist.end<uchar>(), last_hist.begin<uchar>() );
    if (eq)
        cout << "hists equal" << endl;
    else
        cout << "hists not equal" << endl;
}
else
    first = false;

//draw histogram
for (int i = 1; i < *histSize; i++)
//...

if(!frame.empty())imshow("Frame", frame);
v_hist.copyTo(last_hist);

if (waitKey(30) >= 0) break;
//from here to end is the same

Use of the STL equal() in the conditional statement after normalize() came from how to check whether two matrixes are identical in OpenCV .

When I run this code, I'll see "hists not equal" printed for a few frames after the foreground mask is sufficiently disturbed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM