ofCvContourFinder -> ofCvGrayscaleImage

Hello,

I am writing a blob tracking application and would like to display a history of the activity by adding all blobs at each iteration to the same ofCvGrayscaleImage. My idea is:

  • to have a main image and a temp image,
  • to draw the contours to the temp image,
  • to cvScaleAdd(…) the temp image to the main one,
  • and to display the main image.

I’ve got the scale and add thing working, just add the following code to ofCvGrayscaleImage.cpp.

  
  
//-------------------------------------------------------------------------------------  
void ofCvGrayscaleImage::scaleAdd(float scalar, ofCvGrayscaleImage & mom) {  
    if (mom.width == width && mom.height == height){  
		cvScaleAdd(cvImage, cvScalar(scalar), mom.getCvImage(), cvImageTemp);  
		swapTemp();  
	} else {  
		printf("error in scaleAdd, images are different sizes\n");  
	}  
}  
  

But I don’t know how to draw the contours off-screen. Is there a way to draw the ofCvContourFinder contours to an ofCvGrayscaleImage?

Thanks,

this is some code you could add to the ofCvGrayscaleImage class, that would allow you to draw a blob into it.

  
  
//-------------------------------------------------------------------------------------  
void  ofCvGrayscaleImage::draw(ofCvBlob blob, int color){  
  
       if (blob.nPts > 0 ){  
               CvPoint * pts = new CvPoint[blob.nPts];  
               for (int i = 0; i < blob.nPts ; i++){  
                       pts[i].x = blob.pts[i].x;  
                       pts[i].y = blob.pts[i].y;  
               }  
               cvFillPoly( cvImage,&pts, &(blob.nPts),1,  
                       CV_RGB(color,color,color));  
               delete pts;  
  
       }  
}  
  

you could then draw all of the blobs found into an image, or the largest one, draw them in different colors, etc.

I hope that helps -
zach

But I don’t know how to draw the contours off-screen.
Is there a way to draw the ofCvContourFinder contours to an
ofCvGrayscaleImage?

hi prisionerjohn

well i’m not an expert there, but i’ve been looking for similar problems as yours and find out how an off-screen renderign could be done in OpenGL.

it’s totally out of OF code but i give u this link where the technique is explained in case it gives u some ideas …

http://www.opengl.org/registry/specs/EX-…-object.txt

…/…

This extension defines a simple interface for drawing to rendering
destinations other than the buffers provided to the GL by the
window-system.

Hi again,

I tried Zach’s code and it works well. I just changed “cvFillPoly(…)” for “cvPolyLine(…)” in order to get outlines.

But I have a new problem with my home-made “scaleAdd(…)” which is shown in my first post. I don’t get any compilation errors, but as soon as I call it, the application quits and I get the following error:

  
  
OpenCV ERROR: Unsupported format or combination of formats ()  
	in function cvScaleAdd, /Users/theo/Documents/code/__openFrameworks/sandbox/__openCV/openCVCompile/_make/../cxcore/src/cxmatmul.cpp(2306)  
Terminating the application...  
/Users/theo/Documents/code/__openFrameworks/sandbox/__openCV/openCVCompile/_make/../cxcore/src/cxerror.cpp:360: failed assertion `0'  
  

I’m not too sure what that means, but here is the call:

  
historyChannel.scaleAdd(0.5f, blobChannel);  

Both “historyChannel” and “blobChannel” are ofCvGrayscaleImages and have been allocated. In fact, it works fine if I replace the line above with:

  
historyChannel += blobChannel;  

Any ideas?
And thanks in advance for the help :wink:

sorry - I played around with it, but I couldn’t get cvScaleAdd to work, no matter what I tried… It could be a bug with opencv.

here is a hand crafted (and therefore not necessarily optimized ! ) version of a blend function, which allows you to blend one grayscale image into another (because there isn’t a great way to do this elsewise in opencv):

  
  
// --------------------  
// blend into me  
//  
void ofCvGrayscaleImage::composite(ofCvGrayscaleImage mom,ofCvGrayscaleImage momsAlpha){  
	  
	// for now just mode ATOP...  
	// but we should add, over, in etc...  
	// [http://www.gamedev.net/reference/articles/article320.asp](http://www.gamedev.net/reference/articles/article320.asp)  
	  
	if (mom.width == width	&& 	mom.height == height){  
		if (momsAlpha.width == width 	&& 	momsAlpha.height == height){  
			 int pos;  
			register unsigned char alphaVal;  
			register unsigned char  val;  
			unsigned char * momData = (unsigned char *)mom.getCvImage()->imageData;  
			unsigned char * momAlphaData = (unsigned char *)momsAlpha.getCvImage()->imageData;  
			unsigned char * meData = (unsigned char *)cvImage->imageData;  
			  
			int result 	= 0;  
			pos = 0;  
			for (int i = 0; i < height; i++){  
				for (int j = 0; j < width; j++){  
					alphaVal 			= 	*(momAlphaData + pos);  
					*(meData + pos) 	= ((*(meData + pos)*(255-alphaVal)) +   
											(*(momData + pos) * alphaVal)) >> 8;   
					pos++;  
				}  
				pos = i * cvImage->widthStep;  
			}  
		}  
	}  
}  
// --------------------  
  

I hope this helps. you may discover that grayscale images (0-255) don’t have a high amount of resolution for blending, so certain things, like very slowly blurring in the background, etc, are better done with floating point images (you can see chris’s post in examples about this).

take care!
zach

sorry - my bad, this is not exactly what you want:

this does blending of one image into another using a third as an alpha

you would like to use a constant as an alpha. I this I’ve written this, I will keep looking for it. I keep the above code up though, cause it could be useful -z

Hi Zach,
I thought it might be an OpenCV bug from that error message…
But I managed to do it this way (“historyChannel” and “blobChannel” are both ofCvGrayscaleImages, “scalar” is a float between 0 and 1):

  
  
historyChannel -= (1.0-scalar)*255;  
historyChannel += blobChannel;  
  

You can also add the following to ofCvGrayscaleImage.cpp:

  
  
//-------------------------------------------------------------------------------------  
void ofCvGrayscaleImage::scaleAdd(float scalar, ofCvGrayscaleImage & mom) {  
    if (mom.width == width && mom.height == height) {  
        *this -= (1.0f-scalar)*255;  
        *this += mom;  
    } else {  
        printf("error in scaleAdd, images are different sizes\n");  
    }  
}  
  

hi –

cool, I’m glad you got it to work. I should point out that what you coded isn’t exactly the equivalent of scaleAdd since it’s subtracting a constant value. for example, if you have a constant of 0.5,

(1.0-scalar)*255 = 128 (more accurately 127.5)

so, with incoming pixels, when you do -=

255 - 128 = 127
254 - 128 = 126…
etc
60 - 128 = 0 (since there are no negative values for -=)

what I think scaleAdd would do, is

255 * 0.5 = 127
60 * 0.5 = 30

etc…

so there is a difference, but subtracting will still have a similar type effect (darkening the pixel values) as multiplying by a percentage.

thanks for posting !
take care,
zach