I want to detect a face using the Haar algorithm in OpenCV and draw it in another area.
I’m able to draw a white box around faces in the correct place on the original image.
However, when I copy the region of the pixels detected by Haar into an ofTexture and draw it somewhere else on the screen, something strange happens.
The image that gets drawn is the same size as the face, but the pixels are not in the correct place.
If I put my face somewhere near the center, it will be lined up correctly, but if I move out of the center, the image pans, so it’s almost as if my face is a cursor showing which region of the x-y plane to show in the copied image.
I’m using some of the ofxCvHaarFinderExample addon code and injecting some of nick_k’s code:
http://forum.openframeworks.cc/t/face-tracking/167/0
download/file.php?id=7
Here is my code:
// testApp.h
#pragma once
#include "ofMain.h"
#include "ofxCvHaarFinder.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 img;
ofxCvHaarFinder finder;
ofVideoGrabber vidGrabber;
ofxCvColorImage colorImg;
ofxCvGrayscaleImage grayImage;
ofxCvGrayscaleImage grayBg;
ofxCvGrayscaleImage grayDiff;
ofxCvContourFinder contourFinder;
int threshold;
bool bLearnBakground;
ofTexture cropTexture;
unsigned char * pixels;
};
// testApp.cpp
#include "testApp.h"
//--------------------------------------------------------------
void testApp::setup(){
vidGrabber.setVerbose(true);
vidGrabber.initGrabber(320,240);
colorImg.allocate(320,240);
grayImage.allocate(320,240);
grayBg.allocate(320,240);
grayDiff.allocate(320,240);
bLearnBakground = true;
threshold = 80;
//img.loadImage("test.jpg");
finder.setup("haarcascade_frontalface_default.xml");
//finder.findHaarObjects(img);
}
//--------------------------------------------------------------
void testApp::update(){
ofBackground(100,100,100);
bool bNewFrame = false;
vidGrabber.grabFrame();
bNewFrame = vidGrabber.isFrameNew();
if (bNewFrame){
pixels = vidGrabber.getPixels();
colorImg.setFromPixels(pixels, 320,240);
grayImage = colorImg;
if (bLearnBakground == true){
grayBg = grayImage; // the = sign copys the pixels from grayImage into grayBg (operator overloading)
bLearnBakground = false;
}
// take the abs value of the difference between background and incoming and then threshold:
grayDiff.absDiff(grayBg, grayImage);
grayDiff.threshold(threshold);
// find contours which are between the size of 20 pixels and 1/3 the w*h pixels.
// also, find holes is set to true so we will get interior contours as well....
contourFinder.findContours(grayDiff, 20, (340*240)/3, 10, true); // find holes
finder.findHaarObjects(grayDiff);
}
}
//--------------------------------------------------------------
void testApp::draw(){
colorImg.draw(0,0);
glPushMatrix();
if (finder.blobs.size() > 0) {
ofRectangle cur = finder.blobs[0].boundingRect;
float x,y,w,h;
int cropWidth;
int cropHeight;
int haarfinderx;
int haarfindery;
int mainPixelPos;
int subPixlPos;
int camWidth = 320;
x = finder.blobs[0].boundingRect.x;
y = finder.blobs[0].boundingRect.y;
w = finder.blobs[0].boundingRect.width;
h = finder.blobs[0].boundingRect.height;
cropWidth = (int) w;
cropHeight = (int) h;
haarfinderx = (int) x;
haarfindery = (int) y;
cropTexture.allocate(cropWidth, cropHeight, GL_RGB);
unsigned char subRegion[ cropWidth * cropHeight * 3 ]; // R G B
for (int i = 0; i < cropHeight; i++) {
for (int j = 0; j < cropWidth; j++) {
mainPixelPos = ((j+haarfinderx) * camWidth + (i+haarfindery)) * 3;
subPixlPos = (j * cropWidth + i) * 3;
subRegion[subPixlPos] = pixels[mainPixelPos]; // R
subRegion[subPixlPos + 1] = pixels[mainPixelPos + 1]; // G
subRegion[subPixlPos + 2] = pixels[mainPixelPos + 2]; // B
}
}
cropTexture.loadData(subRegion, cropWidth, cropHeight, GL_RGB);
glPushMatrix();
cropTexture.draw(500, 500);
glPopMatrix();
}
glPushMatrix();
ofNoFill();
for(int i = 0; i < finder.blobs.size(); i++) {
ofRectangle cur = finder.blobs[i].boundingRect;
ofRect(cur.x, cur.y, cur.width, cur.height);
}
}
//--------------------------------------------------------------
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){
}