Working with openCv functions

Spent the day figuring out how to use openCv functions with openFrameworks, and thought I’d share the results with the world.
Not sure this is the best place, but I would have liked this to be here this morning :slight_smile:

The example used loads a mask map(?) from a png file and allows you to select which are of the image you want to crop out based on the colour of the mask.
The goal is to have a contour finder run on only sections of an image.

The xcode project : http://bit.ly/theronOf4712
Tried to give sound advice, but if im wrong, let me know :slight_smile:

  
  
	//Integers to set the height and width of our workspace  
	int width, height;  
	  
	//The grabber that gets frames from the webcam  
	ofVideoGrabber vidGrabber;  
	//An ofImage so that we can load in an image file  
	//Im not sure if this can be done directly with cvImages, if so, let me know  
	ofImage	ofMask;  
	  
	//Some openCv images  
	ofxCvColorImage cvImage, cvMask,  cvBlank, cvDest;  
	ofxCvGrayscaleImage cvGrayMask;  
	  
	//And some pointers to IplImages (openCv's native image format)  
	//These cant be on the same line for some reason???  
	IplImage * iplImg;  
	IplImage * iplMask;  
	IplImage * iplGrayMask;  
	IplImage * iplDest;  

  
  
/*  
 Theron Burger 2011  
 pftburger@gmail.com  
 theronBurger.com  
   
 Some notes on dealing with openCv functions  
   
 some functions give a destination.  
 If the program crashes (with "Program received signal:  “SIGABRT” ")  
 and says "Previous frame inner to this frame (gdb could not unwind past this frame)"  
 check if the destination needs to be a single channel image (grayscale)  
   
 some functions require a cvScalar type  
 this can be created with the cvScalar() or cvScalarAll() functions  
 cvScalar takes 4 doubles (doubles are "double accuracy" floats) IE Red, Blue, Green and Alpha  
 cvScalarAll takes one double, and sets all four to the same thing.  
   
 iplImages are the image format openCv uses.  
 IPL stands for Image Processing Library  
 they can be one channel (grayscale), three channel (RGB), or four channel (RGB+Alpha)  
  
 oh, and generally, if you get a “EXC_BAD_ACCESS” error  
 it means that you tried to access something where nothing exists.  
 try allocating all your images before hand, check that the png file exists, and if you have any loops  
 make sure you counter stays within the range of the object.  
   
 */  
#include "testApp.h"  
  
//--------------------------------------------------------------  
void testApp::setup() {  
	  
	//Set up the scene, the mask map must be the same size!  
	width	= 400;  
	height	= 300;  
	  
	//pre allocate all the images. This helps by giving the empty containers a size  
	//so that if we query them, we dont get out of range  
	cvImage.allocate(width,height);  
	cvMask.allocate(width,height);  
	cvGrayMask.allocate(width,height);  
	cvBlank.allocate(width,height);  
	cvDest.allocate(width,height);  
	  
	//Start the video grabber, this gets an image stream from the webcam  
	vidGrabber.initGrabber(width, height);  
	  
	//Load up the mask image  
	//This image needs to be pre-made in photoshop using the pencil tool, in dissolve mode  
	//This is important, as the brush tool tries to blend the edges, causing blurred edges  
	//When we run the cvInRangeS function on a blurred edge, we get little dots on the mask  
	//These little dots cause islands in the final image, and create false blobs because of their size  
	//Load the image into a ofImage  
	ofMask.loadImage("mask.png");  
	//copy it to a cvColorImage  
	cvMask.setFromPixels(ofMask.getPixels(), width, height);  
	//then copy it to a cvGrascaleImage  
	cvGrayMask = cvMask;   
	  
	//Assign pointers to the iplImages hidden inside the   
	iplMask		= cvMask.getCvImage();  
	iplGrayMask	= cvGrayMask.getCvImage();  
	iplDest		= cvDest.getCvImage();  
	iplImg		= cvImage.getCvImage();  
	  
	//Now that we have the mask map, we need to extract only the section we are interested in  
	//To do that, we select a colour, and copy only the parts of the image that match  
	//Set the colour "key" we are looking for in the mask map  
	double key = 204;  
	//The destination iplImage must be single channel :)  
	cvInRangeS(iplMask, cvScalarAll(key-1), cvScalarAll(key+1), iplGrayMask);  
	//We should flag the cvImage as change, but it seems to work without it.  
	//cvGrayMask.flagImageChanged();  
  
  
}  
  
//--------------------------------------------------------------  
void testApp::update() {  
	//Update the vidGrabber  
	vidGrabber.update();  
	  
	//Check if the webcam has captured a new frame  
	if (vidGrabber.isFrameNew()) {  
		//get the new frame from the vidGrabber and copy it to the cvImage  
		cvImage.setFromPixels(vidGrabber.getPixels(), width, height);  
		  
		//Here we copy the image from iplImg to iplDest, only where iplGrayMask is nonZero ie, not black  
		//Once again, mask must be a single channel image  
		cvCopy(iplImg, iplDest, iplGrayMask);  
		  
		//Tell cvDest that we have updated its cvImage, so that it can do its magic  
		//If we dont do this, we wont see anything when we draw the image  
		//This time it seems to be necessary :P  
		cvDest.flagImageChanged();  
	}  
}  
  
//--------------------------------------------------------------  
void testApp::draw() {  
	//Draw a mid gray background  
	ofBackground(127.5f);  
	//Make sure the "pen" colour is white, if its not, the images will be shaded the current pen colour  
	ofSetColor(255);  
	//draw all the images to the screen  
	cvImage.draw(10,10);  
	cvDest.draw(420,10);  
	cvMask.draw(10,320);  
	cvGrayMask.draw(420,320);  
	  
}  
  

some keywords for search

convert IplImage to cvImage
convert IplImage to ofxCvColorImage
convert IplImage to ofxCvGrayscaleImage
convert IplImage to openCv Image
Draw IplImage
use openCv functions
image mask
mask from jpg
mask from png
cvScalar()
cvInRange
cvCopy

Hi theron,

thank you for your code.
I get a bad access code… sometimes…
and sometimes the app works, but do not get the images, except the captured one.

i will try to look for the reason…

You get bad access?
Hmmm, odd, without changing anything?

and if I read right, only the top left image (cvImage) is displayed? Even more odd

Are you using of6 or the latest build off github?

Id love to here if you solve them.
The code works for me though, so it sounds like something is funny with your openCV

Do other openCV functions work?

Hi theron,

i am in of 006.
now i do not get any bad access code.
video captured is displayed ok. others are black and png image is displayed in a strange way…
Probably something with the .png image. I did one of the same size as the others 400x300. will try another…

ah, right, make sure “key” is set to the exact colour your trying to match in your png.

For debugging, you could make a pure white png and set the key to 255.
What way, you can check if openCV doing its thing, as the entire video should be copied across.

if that doesnt work, you could also just leave out the mask all together as a test, and just use
cvCopy(iplImg, iplDest);