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?