blob: ba4877eaa15abd61881519d9595b95a72c604446 [file] [log] [blame]
diff --git a/src/filter/alpha0ps/alpha0ps.c b/src/filter/alpha0ps/alpha0ps.c
old mode 100755
new mode 100644
diff --git a/src/filter/alpha0ps/alphagrad.c b/src/filter/alpha0ps/alphagrad.c
old mode 100755
new mode 100644
diff --git a/src/filter/alpha0ps/alphaspot.c b/src/filter/alpha0ps/alphaspot.c
old mode 100755
new mode 100644
diff --git a/src/filter/blur/IIRblur.c b/src/filter/blur/IIRblur.c
old mode 100755
new mode 100644
diff --git a/src/filter/coloradj/coloradj_RGB.c b/src/filter/coloradj/coloradj_RGB.c
old mode 100755
new mode 100644
diff --git a/src/filter/denoise/hqdn3d.c b/src/filter/denoise/hqdn3d.c
old mode 100755
new mode 100644
diff --git a/src/filter/facebl0r/facebl0r.cpp b/src/filter/facebl0r/facebl0r.cpp
index 17446cc..fa21a35 100644
--- a/src/filter/facebl0r/facebl0r.cpp
+++ b/src/filter/facebl0r/facebl0r.cpp
@@ -22,49 +22,49 @@
#include "frei0r.hpp"
#include "frei0r_math.h"
-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
+class TrackedObj {
+public:
+ void update_hist();
+ void update_hue_image (const cv::Mat& image);
+ cv::RotatedRect camshift_track_face();
+
+ cv::Mat hsv; //input image converted to HSV
+ cv::Mat hue; //hue channel of HSV image
+ cv::Mat mask; //image for masking pixels
+ cv::Mat prob; //face probability estimates for each pixel
- CvHistogram* hist; //histogram of hue in original face image
+ cv::Mat hist; //histogram of hue in original face image
+ static const int hist_bins; //number of histogram bins
+ static const float hist_range[2]; //histogram range
+
+ cv::Rect prev_rect; //location of face in previous frame
+ cv::RotatedRect curr_box; //current face location estimate
+};
- CvRect prev_rect; //location of face in previous frame
- CvBox2D curr_box; //current face location estimate
-} TrackedObj;
+const float TrackedObj::hist_range[2] = { 0, 180 };
+const int TrackedObj::hist_bins = 30;
class FaceBl0r: public frei0r::filter {
public:
FaceBl0r(int wdt, int hgt);
- ~FaceBl0r();
+ ~FaceBl0r() = default;
void update(double time,
uint32_t* out,
const uint32_t* in);
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*);
-
+ std::vector<cv::Rect> detect_face();
+
+ TrackedObj tracked_obj;
- 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;
+ cv::Mat image;
- CvHaarClassifierCascade* cascade;
- CvMemStorage* storage;
+ cv::CascadeClassifier cascade;
// plugin parameters
std::string classifier;
@@ -77,7 +77,6 @@ class FaceBl0r: public frei0r::filter {
double largest;
std::string old_classifier;
-
unsigned int face_found;
unsigned int face_notfound;
@@ -87,18 +86,12 @@ class FaceBl0r: public frei0r::filter {
frei0r::construct<FaceBl0r> plugin("FaceBl0r",
"automatic face blur",
"ZioKernel, Biilly, Jilt, Jaromil, ddennedy",
- 1,1, F0R_COLOR_MODEL_PACKED32);
+ 1,1, F0R_COLOR_MODEL_BGRA8888);
FaceBl0r::FaceBl0r(int wdt, int hgt) {
- face_rect = 0;
- image = 0;
- tracked_obj = 0;
face_found = 0;
-
- cascade = 0;
- storage = 0;
-
+
classifier = "/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml";
register_param(classifier,
"Classifier",
@@ -120,52 +113,35 @@ FaceBl0r::FaceBl0r(int wdt, int hgt) {
register_param(largest, "Largest", "Maximum object size in pixels, divided by 10000");
}
-FaceBl0r::~FaceBl0r() {
- if(tracked_obj)
- destroy_tracked_object(tracked_obj);
-
- if(cascade) cvReleaseHaarClassifierCascade(&cascade);
- if(storage) cvReleaseMemStorage(&storage);
-
-}
-
void FaceBl0r::update(double time,
uint32_t* out,
- const uint32_t* in) {
-
- if (!cascade) {
- cvSetNumThreads(cvRound(threads * 100));
- if (classifier.length() > 0) {
- if (classifier == old_classifier) {
- // same as before, avoid repeating error messages
- memcpy(out, in, size * 4); // of course assuming we are RGBA only
- return;
- } else old_classifier = classifier;
-
- cascade = (CvHaarClassifierCascade*) cvLoad(classifier.c_str(), 0, 0, 0 );
- if (!cascade) {
- fprintf(stderr, "ERROR in filter facebl0r, classifier cascade not found:\n");
- fprintf(stderr, " %s\n", classifier.c_str());
- memcpy(out, in, size * 4);
- return;
- }
- storage = cvCreateMemStorage(0);
- }
- else {
- memcpy(out, in, size * 4);
- return;
- }
- }
+ const uint32_t* in)
+{
+ if (cascade.empty()) {
+ cv::setNumThreads(cvRound(threads * 100));
+ if (classifier.length() == 0 || classifier == old_classifier) {
+ // same as before, avoid repeating error messages
+ memcpy(out, in, size * 4); // of course assuming we are RGBA only
+ return;
+ }
+ old_classifier = classifier;
+ }
+
+ if (!cascade.load(classifier.c_str())) {
+ fprintf(stderr, "ERROR in filter facebl0r, classifier cascade not found:\n");
+ fprintf(stderr, " %s\n", classifier.c_str());
+ memcpy(out, in, size * 4);
+ return;
+ }
// sanitize parameters
recheck = CLAMP(recheck, 0.001, 1.0);
search_scale = CLAMP(search_scale, 0.11, 1.0);
neighbors = CLAMP(neighbors, 0.01, 1.0);
- if( !image )
- image = cvCreateImage( cvSize(width,height), IPL_DEPTH_8U, 4 );
-
- memcpy(image->imageData, in, size * 4);
+ // copy input image to OpenCV
+ image = cv::Mat(height, width, CV_8UC4, (void*)in);
+ tracked_obj.update_hue_image(image);
/*
no face*
@@ -176,27 +152,24 @@ void FaceBl0r::update(double time,
no face*
*/
if(face_notfound>0) {
-
+ std::vector<cv::Rect> faces;
if(face_notfound % cvRound(recheck * 1000) == 0)
- face_rect = detect_face(image, cascade, storage);
+ faces = detect_face();
// if no face detected
- if (!face_rect) {
+ if (faces.empty()) {
face_notfound++;
} else {
- //track detected face with camshift
- if(tracked_obj)
- destroy_tracked_object(tracked_obj);
- tracked_obj = create_tracked_object(image, face_rect);
+ tracked_obj.prev_rect = faces[0];
+ tracked_obj.update_hist();
face_notfound = 0;
face_found++;
}
-
}
- if(face_found>0) {
+ if (face_found > 0) {
//track the face in the new frame
- face_box = camshift_track_face(image, tracked_obj);
+ cv::RotatedRect face_box = tracked_obj.camshift_track_face();
int min = cvRound(smallest * 1000);
min = min? min : 10;
@@ -210,17 +183,13 @@ void FaceBl0r::update(double time,
face_notfound++;
}
else {
-////////////////////////////////////////////////////////////////////////
- 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);
-////////////////////////////////////////////////////////////////////////
-
+ cv::Rect blur_region = tracked_obj.prev_rect & cv::Rect({0, 0}, image.size());
+ cv::Mat blur(image, blur_region);
+ cv::blur(blur, blur, {23, 23}, cv::Point(-1, -1));
+
//outline face ellipse
if (ellipse)
- cvEllipseBox(image, face_box, CV_RGB(255,0,0), 2, CV_AA, 0);
+ cv::ellipse(image, face_box, CV_RGB(255,0,0), 2, cv::LINE_AA);
face_found++;
if(face_found % cvRound(recheck * 1000) == 0)
@@ -228,133 +197,76 @@ void FaceBl0r::update(double time,
}
}
- memcpy(out, image->imageData, size * 4);
- cvReleaseImage(&image);
+ memcpy(out, image.data, size * 4);
}
/* Given an image and a classider, detect and return region. */
-CvRect* FaceBl0r::detect_face (IplImage* image,
- CvHaarClassifierCascade* cascade,
- CvMemStorage* storage) {
-
- CvRect* rect = 0;
-
- if (cascade && storage) {
+std::vector<cv::Rect> FaceBl0r::detect_face()
+{
+ if (cascade.empty()) {
+ return std::vector<cv::Rect>();
+ }
+
//use an equalized gray image for better recognition
- IplImage* gray = cvCreateImage(cvSize(image->width, image->height), 8, 1);
- cvCvtColor(image, gray, CV_BGR2GRAY);
- cvEqualizeHist(gray, gray);
- cvClearMemStorage(storage);
+ cv::Mat gray;
+ cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
+ cv::equalizeHist(gray, gray);
//get a sequence of faces in image
int min = cvRound(smallest * 1000);
- CvSeq *faces = cvHaarDetectObjects(gray, cascade, storage,
+ std::vector<cv::Rect> faces;
+ cascade.detectMultiScale(gray, faces,
search_scale * 10.0,
cvRound(neighbors * 100),
- CV_HAAR_FIND_BIGGEST_OBJECT|//since we track only the first, get the biggest
- CV_HAAR_DO_CANNY_PRUNING, //skip regions unlikely to contain a face
- cvSize(min, min));
-
- //if one or more faces are detected, return the first one
- if(faces && faces->total)
- rect = (CvRect*) cvGetSeqElem(faces, 0);
-
- cvReleaseImage(&gray);
- }
+ cv::CASCADE_FIND_BIGGEST_OBJECT|//since we track only the first, get the biggest
+ cv::CASCADE_DO_CANNY_PRUNING, //skip regions unlikely to contain a face
+ cv::Size(min, min));
- return rect;
+ return faces;
}
-/* 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;
-
+void TrackedObj::update_hist()
+{
//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);
+ cv::Mat hue_roi(hue, prev_rect);
+ cv::Mat mask_roi(mask, prev_rect);
- free(obj);
+ const float* range = hist_range;
+ cv::calcHist(&hue_roi, 1, nullptr, mask_roi, hist, 1, &hist_bins, &range);
+ normalize(hist, hist, 0, 255, cv::NORM_MINMAX);
}
/* 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);
-
+cv::RotatedRect TrackedObj::camshift_track_face()
+{
//create a probability image based on the face histogram
- cvCalcBackProject(&obj->hue, obj->prob, obj->hist);
- cvAnd(obj->prob, obj->mask, obj->prob, 0);
+ const float* range = hist_range;
+ cv::calcBackProject(&hue, 1, nullptr, hist, prob, &range);
+ prob &= mask;
//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);
+ cv::RotatedRect curr_box = CamShift(prob, prev_rect,
+ cv::TermCriteria(cv::TermCriteria::EPS | cv::TermCriteria::MAX_ITER, 10, 1 ));
- //update face location and angle
- obj->prev_rect = components.rect;
- obj->curr_box.angle = -obj->curr_box.angle;
+ //update face location
+ prev_rect = curr_box.boundingRect();
- return obj->curr_box;
+ return curr_box;
}
-void FaceBl0r::update_hue_image (const IplImage* image, TrackedObj* obj) {
+void TrackedObj::update_hue_image (const cv::Mat& image) {
//limits for calculating hue
int vmin = 65, vmax = 256, smin = 55;
-
+
//convert to HSV color model
- cvCvtColor(image, obj->hsv, CV_BGR2HSV);
-
+ cv::cvtColor(image, hsv, cv::COLOR_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
-
+ cv::inRange(hsv, //source
+ cv::Scalar(0, smin, MIN(vmin, vmax)), //lower bound
+ cv::Scalar(180, 256, MAX(vmin, vmax)), //upper bound
+ mask); //destination
+
//extract the hue channel, split: src, dest channels
- cvSplit(obj->hsv, obj->hue, 0, 0, 0 );
+ cv::extractChannel(hsv, hue, 0);
}
diff --git a/src/filter/facedetect/facedetect.cpp b/src/filter/facedetect/facedetect.cpp
index 1906962..580b53b 100644
--- a/src/filter/facedetect/facedetect.cpp
+++ b/src/filter/facedetect/facedetect.cpp
@@ -148,13 +148,13 @@ class FaceDetect: public frei0r::filter
count = 1; // reset the recheck counter
if (objects.size() > 0) // reset the list of objects
objects.clear();
- double elapsed = (double) cvGetTickCount();
+ double elapsed = (double) cv::getTickCount();
objects = detect();
// use detection time to throttle frequency of re-detect vs. redraw (automatic recheck)
- elapsed = cvGetTickCount() - elapsed;
- elapsed = elapsed / ((double) cvGetTickFrequency() * 1000.0);
+ elapsed = cv::getTickCount() - elapsed;
+ elapsed = elapsed / ((double) cv::getTickFrequency() * 1000.0);
// Automatic recheck uses an undocumented negative parameter value,
// which is not compliant, but technically feasible.
@@ -188,7 +188,7 @@ class FaceDetect: public frei0r::filter
}
// use an equalized grayscale to improve detection
- cv::cvtColor(image_roi, gray, CV_BGR2GRAY);
+ cv::cvtColor(image_roi, gray, cv::COLOR_BGR2GRAY);
// use a smaller image to improve performance
cv::resize(gray, small, cv::Size(cvRound(gray.cols * scale), cvRound(gray.rows * scale)));
@@ -249,8 +249,8 @@ class FaceDetect: public frei0r::filter
{
cv::Rect* r = (cv::Rect*) &objects[i];
cv::Point center;
- int thickness = stroke <= 0? CV_FILLED : cvRound(stroke * 100);
- int linetype = antialias? CV_AA : 8;
+ int thickness = stroke <= 0? cv::FILLED : cvRound(stroke * 100);
+ int linetype = antialias? cv::LINE_AA : 8;
center.x = cvRound((r->x + r->width * 0.5) / scale);
center.y = cvRound((r->y + r->height * 0.5) / scale);
diff --git a/src/filter/medians/medians.c b/src/filter/medians/medians.c
old mode 100755
new mode 100644
diff --git a/src/filter/select0r/select0r.c b/src/filter/select0r/select0r.c
old mode 100755
new mode 100644
diff --git a/src/filter/sharpness/sharpness.c b/src/filter/sharpness/sharpness.c
old mode 100755
new mode 100644