CvHistogram Progress being made.

Could one of you lovely people look through this and see if I’m doing anything blatantly wrong?

I get “OpenCV Error: Bad argument (Invalid histogram header) in unknown function, file src\histogram.cpp, line 1667”

.h

  
#pragma once  
  
//Hacked together from [http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html](http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html)  
  
#include "ofMain.h"  
#include "ofxOpenCv.h"  
  
//#define _USE_LIVE_VIDEO		// uncomment this to use a live camera  
								// otherwise, we'll use a movie file  
  
class testApp : public ofBaseApp{  
  
	public:  
		void setup();  
		void update();  
		void draw();  
		  
		void keyPressed(int key);  
		void keyReleased(int key);  
		void mouseMoved(int x, int y );  
		void mouseDragged(int x, int y, int button);  
		void mousePressed(int x, int y, int button);  
		void mouseReleased(int x, int y, int button);  
		void windowResized(int w, int h);  
		void dragEvent(ofDragInfo dragInfo);  
		void gotMessage(ofMessage msg);		  
  
        #ifdef _USE_LIVE_VIDEO  
		  ofVideoGrabber 		vidGrabber;  
		#else  
		  ofVideoPlayer 		vidPlayer;  
		#endif  
  
        ofxCvColorImage			colorImg;  
		ofxCvColorImage			hsvImg;  
		ofxCvColorImage			outHistImg;  
		ofxCvColorImage			outImg;  
  
        ofxCvGrayscaleImage 	grayImage;  
		ofxCvGrayscaleImage 	grayBg;  
		ofxCvGrayscaleImage 	grayDiff;  
		ofxCvGrayscaleImage 	ofHplane;  
		ofxCvGrayscaleImage 	ofSplane;  
		ofxCvGrayscaleImage 	ofVplane;  
  
		IplImage*				vidImage;  
		IplImage*				img;  
		IplImage*				back_img;  
		IplImage*				hsv;  
		IplImage*				h_plane;  
		IplImage*				s_plane;  
		IplImage*				v_plane;  
		IplImage*				hist_img;  
		//IplImage*				planes;   
         
  
		CvHistogram*				hist;  
		  
  
		unsigned char *			grayDiffPixels;  
  
		int 				threshold;  
		float				diffPercent;  
		int					w;  
		int					h;  
		int					lastFrameCount;  
		bool				bLearnBakground;  
		bool				sceneChange;  
  
		int					h_bins, s_bins;  
  
  
};  
  
  

and .cpp

  
#include "testApp.h"  
  
//--------------------------------------------------------------  
void testApp::setup(){  
  
	#ifdef _USE_LIVE_VIDEO  
        vidGrabber.setVerbose(true);  
        vidGrabber.initGrabber(320,240);  
	#else  
        vidPlayer.loadMovie("movies/Nemo.mov");  
        vidPlayer.play();  
		w = vidPlayer.width;  
		h = vidPlayer.height;  
	#endif  
	  
	//allocate 3 channel images  
	colorImg.allocate(w,h);  
	hsvImg.allocate(w,h);  
	outHistImg.allocate(w,h);  
	outImg.allocate(w,h);  
  
	//allocate 1 channel images  
	ofHplane.allocate(w,h);  
	ofSplane.allocate(w,h);  
	ofVplane.allocate(w,h);  
	grayImage.allocate(w,h);  
	grayBg.allocate(w,h);  
	grayDiff.allocate(w,h);  
  
	//all this is for later  
	bLearnBakground = true;  
	threshold = 20;  
	diffPercent = 0.20;  
	sceneChange = false;  
	grayDiffPixels = new unsigned char [w*h*3];  
  
  
	// Set up images as per Theron's workaround at [http://forum.openframeworks.cc/t/iplimage-to-ofxcvgrayscaleimage-problem/6873/0](http://forum.openframeworks.cc/t/iplimage-to-ofxcvgrayscaleimage-problem/6873/0)  
	   
	img = colorImg.getCvImage();  
	back_img = grayImage.getCvImage();  
	hsv = hsvImg.getCvImage();  
	h_plane = ofHplane.getCvImage();  
	s_plane = ofSplane.getCvImage();  
	v_plane = ofVplane.getCvImage();  
	  
  
}  
  
//--------------------------------------------------------------  
void testApp::update(){  
	ofBackground(100,100,100);  
  
    bool bNewFrame = false;  
  
	#ifdef _USE_LIVE_VIDEO  
       vidGrabber.grabFrame();  
	   bNewFrame = vidGrabber.isFrameNew();  
    #else  
        vidPlayer.idleMovie();  
        bNewFrame = vidPlayer.isFrameNew();  
	#endif  
  
	if (bNewFrame){  
  
		#ifdef _USE_LIVE_VIDEO  
            colorImg.setFromPixels(vidGrabber.getPixels(), 320,240);  
	    #else  
            colorImg.setFromPixels(vidPlayer.getPixels(), w,h);  
        #endif  
		  
  
		if (bLearnBakground == true){  
			grayBg = grayImage;		// the = sign copys the pixels from grayImage into grayBg (operator overloading)  
			bLearnBakground = false;  
		}  
// Compute HSV image and separate into colors  
	  
	cvCvtColor( img, hsv, CV_BGR2HSV );  
	IplImage* planes[] = { h_plane, s_plane };//??? <--- how does this work?  
	cvCvtPixToPlane( hsv, h_plane, s_plane, v_plane, 0 );  
  
	// Build and fill the histogram  
	int h_bins = 30, s_bins = 32;  
	CvHistogram* hist;  
	{  
		int hist_size[] = { h_bins, s_bins };  
		float h_ranges[] = { 0, 180 };  
		float s_ranges[] = { 0, 255 };  
		float* ranges[] = { h_ranges, s_ranges };  
		hist = cvCreateHist( 2, hist_size, CV_HIST_ARRAY, ranges, 1 );  
	}  
  
  
	cvCalcHist( planes, hist, 0, 0 ); // Compute histogram  
	cvNormalizeHist( hist, 20*255 ); // Normalize it  
	  
	}  
  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
	ofSetHexColor(0xffffff);  
	colorImg = img;  
	colorImg.draw(20,20);  
  
	int scale = 10;  
	hist_img = outHistImg.getCvImage();  
	cvZero ( hist_img );  
  
	float max_value = 0;  
	cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 );  
	for( int h = 0; h < h_bins; h++ ){  
		for( int s = 0; s < s_bins; s++ ){  
			float bin_val = cvQueryHistValue_2D( hist, h, s );  
			int intensity = cvRound( bin_val * 255 / max_value );  
			cvRectangle( hist_img, cvPoint( h*scale, s*scale ),  
						cvPoint( (h+1)*scale - 1, (s+1)*scale - 1 ),  
						CV_RGB( intensity, intensity, intensity ),  
						CV_FILLED );  
		}  
	}  
	outImg = hist_img;  
	outImg.draw(600,20);  
	  
  
	cvReleaseImage( &img );  
	cvReleaseImage( &back_img );  
	cvReleaseImage( &hist_img );  
  
  
	  
  
}  
  
//--------------------------------------------------------------  
void testApp::keyPressed(int key){  
  
	switch (key){  
		case ' ':  
			bLearnBakground = true;  
			break;  
		case '+':  
			threshold ++;  
			if (threshold > 255) threshold = 255;  
			break;  
		case '-':  
			threshold --;  
			if (threshold < 0) threshold = 0;  
			break;  
		case 'd':  
			diffPercent +=.01;  
			if (diffPercent > .99) diffPercent = .99;  
			break;  
		case 's':  
			diffPercent -=.01;  
			if (diffPercent < 0.01) diffPercent = 0.01;  
			break;  
	}  
}  
  
//--------------------------------------------------------------  
void testApp::keyReleased(int key){  
  
}  
  
//--------------------------------------------------------------  
void testApp::mouseMoved(int x, int y ){  
  
}  
  
//--------------------------------------------------------------  
void testApp::mouseDragged(int x, int y, int button){  
  
}  
  
//--------------------------------------------------------------  
void testApp::mousePressed(int x, int y, int button){  
  
}  
  
//--------------------------------------------------------------  
void testApp::mouseReleased(int x, int y, int button){  
  
}  
  
//--------------------------------------------------------------  
void testApp::windowResized(int w, int h){  
  
}  
  
//--------------------------------------------------------------  
void testApp::gotMessage(ofMessage msg){  
  
}  
  
//--------------------------------------------------------------  
void testApp::dragEvent(ofDragInfo dragInfo){   
  
}  
  

Any ideas? I’m particualry concerned about the line

  
IplImage* planes[] = { h_plane, s_plane };  

since I can’t allocate the IplImage* like I do all the others according to Theron’s workaround. I have a feeling it’s what’s causing the malformed header, but I’m not sure.

This all compiles fine and there are no errors shown in VS2010.

NovySan

This works for me:

[sup]testApp.h[/sup]

  
/*  
 *  histrogram test  
 *  borrowed and slightly modified from:   
 *	[http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html](http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html)  
 *  
 *  Created by Andreas on 04.08.11.  
 *  Copyright 2011 invertednothing. All rights reserved.  
 *  
 */  
  
#pragma once  
  
#include "ofMain.h"  
  
#include "ofxOpenCv.h"  
  
  
class testApp : public ofBaseApp{  
  
	public:  
		void setup();  
		void update();  
		void draw();  
		  
		void keyPressed(int key);  
		void keyReleased(int key);  
		void mouseMoved(int x, int y );  
		void mouseDragged(int x, int y, int button);  
		void mousePressed(int x, int y, int button);  
		void mouseReleased(int x, int y, int button);  
		void windowResized(int w, int h);  
		void dragEvent(ofDragInfo dragInfo);  
		void gotMessage(ofMessage msg);		  
  
		ofImage					loadImage;  
        ofxCvColorImage			colorImg;  
  
        ofxCvGrayscaleImage 	grayImage;  
		ofxCvGrayscaleImage 	grayBack;  
  
  
};  
  
  

[sup]testApp.cpp[/sup]

  
/*  
 *  histrogram test  
 *  borrowed and slightly modified from:   
 *	[http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html](http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html)  
 *  
 *  Created by Andreas on 04.08.11.  
 *  Copyright 2011 invertednothing. All rights reserved.  
 *  
 */  
  
#include "testApp.h"  
  
//--------------------------------------------------------------  
void testApp::setup(){  
  
  
    colorImg.allocate(320,240);  
	grayImage.allocate(320,240);  
	grayBack.allocate(320,240);  
	  
	loadImage.loadImage( ofToDataPath( "test.jpeg" ) );  
	colorImg.setFromPixels( loadImage.getPixels(), 320, 240 );  
	  
	  
	grayImage = colorImg;  
	  
	CvHistogram* hist;  
	IplImage* iplImageGray;  
	IplImage** plane;  
	  
	iplImageGray = grayImage.getCvImage();  
	plane = &iplImageGray;  
	  
	int hist_size[] = { 30 };  
	float range[] = { 0, 180 };  
	float* ranges[] = { range };  
	hist = cvCreateHist( 1, hist_size, CV_HIST_ARRAY, ranges, 1 );  
	  
	cvCalcHist( plane, hist, 0, 0 );   
	cvNormalizeHist( hist, 20*255 ); // Normalize it  
	  
	cvCalcBackProject( plane, grayBack.getCvImage(), hist );// Calculate back projection  
	cvNormalizeHist( hist, 1.0 ); // Normalize it  
	  
	cvReleaseHist( &hist );  
	  
}  
  
// not really meant to run in a loop ---------------------------  
void testApp::update(){	  
	ofBackground(100,100,100);  
	  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
  
	// draw the incoming, the grayscale, the bg and the thresholded difference  
	ofSetHexColor(0xffffff);  
	colorImg.draw(20,20);  
	grayImage.draw(360,20);  
	grayBack.draw(20,280);  
	  
}  
  
//--------------------------------------------------------------  
void testApp::keyPressed(int key){  
  
}  
  
//--------------------------------------------------------------  
void testApp::keyReleased(int key){  
  
}  
  
//--------------------------------------------------------------  
void testApp::mouseMoved(int x, int y ){  
  
}  
  
//--------------------------------------------------------------  
void testApp::mouseDragged(int x, int y, int button){  
  
}  
  
//--------------------------------------------------------------  
void testApp::mousePressed(int x, int y, int button){  
  
}  
  
//--------------------------------------------------------------  
void testApp::mouseReleased(int x, int y, int button){  
  
}  
  
//--------------------------------------------------------------  
void testApp::windowResized(int w, int h){  
  
}  
  
//--------------------------------------------------------------  
void testApp::gotMessage(ofMessage msg){  
  
}  
  
//--------------------------------------------------------------  
void testApp::dragEvent(ofDragInfo dragInfo){   
  
}  
  

Edit:
Sorry, just realized there is a leak. it has to be

CvHistogram* hist;
and not CvHistogram* hist = new CvHistogram;

Basically an array in c++ is something like a pointer, see here:
http://www.cplusplus.com/doc/tutorial/pointers/

Hmmm, I finally got it working with a still thanks to you. Thanks!

But I need it to work in a loop so I can do scene change detection. I can get it to build and not crash but the histogram renders as white no matter what. I’ll keep poking.

Thanks for helping me get this far!

NovySan

**CORRECTION**

I can see the histogram of the “fingers.mov” just not from the movie I’ve been testing with. The histogram does not update on a per frame basis either.

Ah, I see … you’r working on scene change detection?! I once worked on that for a project but never finished it. Problem was that I had to much false positives … and not really the time to elaborate it further, so in the end I did it manually.

A pity that I can’t find the code anymore :frowning: I remember that I first started with motion detection and later dropped that in favor of using histograms.

Please keep me up to date … would be very interested in how far you get.

By the way I really would go with Kyles ofxCv (https://github.com/kylemcdonald/ofxCv) when working with opencv … the oldscool C interface just sucks!

m9d

p.s.: did you try it using my codesample above … should work?!

Yes, I was able to mash together your code and mine, and have it work with the vidPlayer, but it only creates a histogram for the FIRST frame and doesn’t update after that.

Can you see any reason why the histogram won’t update when the grayImage updates? It is very odd.

I’ll look at Kyle’s stuff right now.

Thanks for all your help!

Got it!!

For some reason you need to manually flag the image the histogram writes into as changed for it to update.

  
grayBack.flagImageChanged();  

Now to construct the scene change detector loop…