Merge branch 'facebl0r'

This commit is contained in:
Jaromil
2010-07-16 12:59:00 +01:00
5 changed files with 338 additions and 33 deletions

View File

@@ -16,6 +16,14 @@ LT_INIT([disable-static])
AC_CONFIG_HEADERS([include/config.h])
if test "x${prefix}" = "xNONE"; then
prefix=${ac_default_prefix}
fi
PACKAGE_LIB_DIR="${prefix}/lib/frei0r-1"
AC_SUBST(PACKAGE_LIB_DIR)
PACKAGE_DATA_DIR="${prefix}/share/frei0r-1"
AC_SUBST(PACKAGE_DATA_DIR)
AC_MSG_CHECKING([host platform])
case $host_os in
*linux*)
@@ -89,13 +97,17 @@ HAVE_OPENCV=false
PKG_CHECK_MODULES(OPENCV, opencv >= 1.0.0, [HAVE_OPENCV=true], [true])
AM_CONDITIONAL([HAVE_OPENCV], [test x$HAVE_OPENCV = xtrue])
if test x$HAVE_OPENCV = xtrue; then
OPENCV_CFLAGS="$OPENCV_CFLAGS -DOPENCV_PREFIX=`pkg-config opencv --variable=prefix`"
# OPENCV_CFLAGS="$OPENCV_CFLAGS -DOPENCV_PREFIX=`pkg-config opencv --variable=prefix`"
AC_DEFINE(HAVE_OPENCV,1,[compiled including opencv])
AC_DEFINE(OPENCV_DATA_DIR,[${prefix}/share/opencv],opencv data prefix)
fi
AC_SUBST(HAVE_OPENCV)
HAVE_GAVL=false
PKG_CHECK_MODULES(GAVL, gavl >= 0.2.3, [HAVE_GAVL=true], [true])
AM_CONDITIONAL([HAVE_GAVL], [test x$HAVE_GAVL = xtrue])
AC_CONFIG_FILES([
frei0r.pc
Makefile
@@ -121,6 +133,7 @@ fi
if test x$HAVE_OPENCV = xtrue; then
echo " - opencv: YES"
echo " data dir: $OPENCV_DATA_DIR"
else
echo " - opencv: NO"
echo " opencv >= 1.0.0 not found - this program enables optional"

View File

@@ -1,35 +1,5 @@
htmldocs_DATA = \
annotated.html \
doxygen.png \
functions.html \
globals.html \
group__icons.html \
hierarchy.html \
structf0r__param__color.html \
tab_b.gif \
dir_c6a51e201754b7c7dc5a21651891d7e2.html \
files.html \
functions_vars.html \
globals_type.html \
group__PARAM__TYPE.html \
index.html \
structf0r__param__info.html \
tab_l.gif \
dirs.html \
frei0r_8h.html \
globals_defs.html \
group__COLOR__MODEL.html \
group__PLUGIN__TYPE.html \
structf0r__param__position.html \
tab_r.gif \
doxygen.css \
frei0r_8h-source.html \
globals_func.html \
group__concurrency.html \
group__pluglocations.html \
modules.html \
structf0r__plugin__info.html \
tabs.css
$(shell ls * | grep -v Makefile)
htmldocsdir=${prefix}/share/doc/${PACKAGE}-1.1/html

View File

@@ -47,6 +47,11 @@ plugin_LTLIBRARIES += facedetect.la
facedetect_la_SOURCES = filter/facedetect/facedetect.c
facedetect_la_CFLAGS = @OPENCV_CFLAGS@ @CFLAGS@
facedetect_la_LIBADD = @OPENCV_LIBS@
plugin_LTLIBRARIES += facebl0r.la
facebl0r_la_SOURCES = filter/facebl0r/facebl0r.cpp
facebl0r_la_CFLAGS = @OPENCV_CFLAGS@ @CFLAGS@
facebl0r_la_LIBADD = @OPENCV_LIBS@
endif
cluster_la_SOURCES = filter/cluster/cluster.c

View File

@@ -0,0 +1,317 @@
/*
* This source code is free software; you can redistribute it and/or
* modify it under the terms of the GNU Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Please refer
* to the GNU Public License for more details.
*
* You should have received a copy of the GNU Public License along
* with this source code; if not, write to: Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <frei0r.hpp>
typedef struct {
IplImage* hsv; //input image converted to HSV
IplImage* hue; //hue channel of HSV image
IplImage* mask; //image for masking pixels
IplImage* prob; //face probability estimates for each pixel
CvHistogram* hist; //histogram of hue in original face image
CvRect prev_rect; //location of face in previous frame
CvBox2D curr_box; //current face location estimate
} TrackedObj;
class FaceBl0r: public frei0r::filter {
public:
FaceBl0r(int wdt, int hgt);
~FaceBl0r();
virtual void update();
private:
// camshift
TrackedObj* create_tracked_object (IplImage* image, CvRect* face_rect);
void destroy_tracked_object (TrackedObj* tracked_obj);
CvBox2D camshift_track_face (IplImage* image, TrackedObj* imgs);
void update_hue_image (const IplImage* image, TrackedObj* imgs);
//trackface
CvRect* detect_face (IplImage*, CvHaarClassifierCascade*, CvMemStorage*);
TrackedObj* tracked_obj;
CvBox2D face_box; //area to draw
CvRect* face_rect;
//used by capture_video_frame, so we don't have to keep creating.
IplImage* image;
CvHaarClassifierCascade* cascade;
CvMemStorage* storage;
int face_found;
int face_notfound;
unsigned int width;
unsigned int height;
unsigned int size; // = width * height
f0r_param_string haarcascade[256];
char classifier[512];
};
frei0r::construct<FaceBl0r> plugin("FaceBl0r",
"automatic face blur ",
"ZioKernel, Biilly, Jilt, Jaromil",
1,0);
FaceBl0r::FaceBl0r(int wdt, int hgt) {
width = wdt;
height = hgt;
size = width*height*4;
sprintf(haarcascade,"frontalface_default");
//initialize
snprintf(classifier,511,"/usr/share/opencv/haarcascades/haarcascade_%s.xml", haarcascade);
fprintf(stderr,"%s\n",classifier);
// para
cascade = (CvHaarClassifierCascade*) cvLoad(classifier, 0, 0, 0 );
storage = cvCreateMemStorage(0);
//validate
assert(cascade && storage);
face_rect = 0;
image = 0;
tracked_obj = 0;
face_found = 0;
face_notfound = 1;
// register_param(haarcascade, "pattern model for recognition",
// "frontalface_alt2, frontalface_alt_tree, frontalface_alt, frontalface_default, fullbody, lowerbody, profileface, upperbody (see in share/opencv/haarcascades)");
}
FaceBl0r::~FaceBl0r() {
if(tracked_obj)
destroy_tracked_object(tracked_obj);
if(cascade) cvReleaseHaarClassifierCascade(&cascade);
if(storage) cvReleaseMemStorage(&storage);
}
void FaceBl0r::update() {
unsigned char *src = (unsigned char *)in;
unsigned char *dst = (unsigned char *)out;
if( !image )
image = cvCreateImage( cvSize(width,height), IPL_DEPTH_8U, 4 );
unsigned char* ipli = (unsigned char*)image->imageData;
memcpy(image->imageData, in, size);
/*
no face*
- look for (detect_face)
yes face
- track face
- no more face
no face*
*/
#define CHECK 25
#define RECHECK 25
if(face_notfound>0) {
if(face_notfound % CHECK == 0)
face_rect = detect_face(image, cascade, storage);
// if no face detected
if (!face_rect) {
face_notfound++;
memcpy(out, image->imageData, size);
return;
} else {
//track detected face with camshift
if(tracked_obj)
destroy_tracked_object(tracked_obj);
tracked_obj = create_tracked_object(image, face_rect);
face_notfound = 0;
face_found++;
}
}
if(face_found>0) {
//track the face in the new frame
face_box = camshift_track_face(image, tracked_obj);
if( ( face_box.size.width < 10 ) // para
|| (face_box.size.height < 10 )
|| (face_box.size.width > 500 )
|| (face_box.size.height > 500 )
) {
face_found = 0;
face_notfound++;
return;
}
////////////////////////////////////////////////////////////////////////
cvSetImageROI (image, tracked_obj->prev_rect);
// cvSmooth (image, image, CV_BLUR, 22, 22, 0, 0);
cvSmooth (image, image, CV_BLUR, 23, 23, 0, 0);
// cvSmooth (image, image, CV_GAUSSIAN, 11, 11, 0, 0);
cvResetImageROI (image);
////////////////////////////////////////////////////////////////////////
//outline face ellipse
cvEllipseBox(image, face_box, CV_RGB(255,0,0), 2, CV_AA, 0);
face_found++;
if(face_found % RECHECK == 0)
face_notfound = 1; // try recheck
}
memcpy(out, image->imageData, size);
cvReleaseImage(&image);
}
/* Given an image and a classider, detect and return region. */
CvRect* FaceBl0r::detect_face (IplImage* image,
CvHaarClassifierCascade* cascade,
CvMemStorage* storage) {
CvRect* rect = 0;
//get a sequence of faces in image
CvSeq *faces = cvHaarDetectObjects(image, cascade, storage,
1.2, //increase search scale by 50% each pass
2, //require 2 neighbors
CV_HAAR_DO_CANNY_PRUNING, //skip regions unlikely to contain a face
cvSize(0, 0)); //use default face size from xml
//if one or more faces are detected, return the first one
if(faces && faces->total)
rect = (CvRect*) cvGetSeqElem(faces, 0);
return rect;
}
/* Create a camshift tracked object from a region in image. */
TrackedObj* FaceBl0r::create_tracked_object (IplImage* image, CvRect* region) {
TrackedObj* obj;
//allocate memory for tracked object struct
if((obj = (TrackedObj *) malloc(sizeof *obj)) != NULL) {
//create-image: size(w,h), bit depth, channels
obj->hsv = cvCreateImage(cvGetSize(image), 8, 3);
obj->mask = cvCreateImage(cvGetSize(image), 8, 1);
obj->hue = cvCreateImage(cvGetSize(image), 8, 1);
obj->prob = cvCreateImage(cvGetSize(image), 8, 1);
int hist_bins = 30; //number of histogram bins
float hist_range[] = {0,180}; //histogram range
float* range = hist_range;
obj->hist = cvCreateHist(1, //number of hist dimensions
&hist_bins, //array of dimension sizes
CV_HIST_ARRAY, //representation format
&range, //array of ranges for bins
1); //uniformity flag
}
//create a new hue image
update_hue_image(image, obj);
float max_val = 0.f;
//create a histogram representation for the face
cvSetImageROI(obj->hue, *region);
cvSetImageROI(obj->mask, *region);
cvCalcHist(&obj->hue, obj->hist, 0, obj->mask);
cvGetMinMaxHistValue(obj->hist, 0, &max_val, 0, 0 );
cvConvertScale(obj->hist->bins, obj->hist->bins,
max_val ? 255.0/max_val : 0, 0);
cvResetImageROI(obj->hue);
cvResetImageROI(obj->mask);
//store the previous face location
obj->prev_rect = *region;
return obj;
}
/* Release resources from tracked object. */
void FaceBl0r::destroy_tracked_object (TrackedObj* obj) {
cvReleaseImage(&obj->hsv);
cvReleaseImage(&obj->hue);
cvReleaseImage(&obj->mask);
cvReleaseImage(&obj->prob);
cvReleaseHist(&obj->hist);
free(obj);
}
/* Given an image and tracked object, return box position. */
CvBox2D FaceBl0r::camshift_track_face (IplImage* image, TrackedObj* obj) {
CvConnectedComp components;
//create a new hue image
update_hue_image(image, obj);
//create a probability image based on the face histogram
cvCalcBackProject(&obj->hue, obj->prob, obj->hist);
cvAnd(obj->prob, obj->mask, obj->prob, 0);
//use CamShift to find the center of the new face probability
cvCamShift(obj->prob, obj->prev_rect,
cvTermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1),
&components, &obj->curr_box);
//update face location and angle
obj->prev_rect = components.rect;
obj->curr_box.angle = -obj->curr_box.angle;
return obj->curr_box;
}
void FaceBl0r::update_hue_image (const IplImage* image, TrackedObj* obj) {
//limits for calculating hue
int vmin = 65, vmax = 256, smin = 55;
//convert to HSV color model
cvCvtColor(image, obj->hsv, CV_BGR2HSV);
//mask out-of-range values
cvInRangeS(obj->hsv, //source
cvScalar(0, smin, MIN(vmin, vmax), 0), //lower bound
cvScalar(180, 256, MAX(vmin, vmax) ,0), //upper bound
obj->mask); //destination
//extract the hue channel, split: src, dest channels
cvSplit(obj->hsv, obj->hue, 0, 0, 0 );
}

View File

@@ -94,7 +94,7 @@ revisioning system *GIT*
: git clone git://code.dyne.org/frei0r.git
Daily snapshots are also packed ready to "./configure; make" on
[[http://ftp.dyne.org/frei0r/][FTP.dyne.org]]
[[http://www.piksel.no/frei0r/snapshot/][www.piksel.no/frei0r/snapshot]]
** Debian / Ubuntu