Move objdetect HaarCascadeClassifier and HOGDescriptor to contrib xobjdetect (#25198)

* Move objdetect parts to contrib

* Move objdetect parts to contrib

* Minor fixes.
This commit is contained in:
WU Jia 2024-03-22 04:40:10 +08:00 committed by GitHub
parent 213e1a4d9d
commit aa5ea340f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
111 changed files with 22 additions and 741097 deletions

View File

@ -1036,7 +1036,7 @@ ocv_register_modules()
add_subdirectory(doc)
# various data that is used by cv libraries and/or demo applications.
add_subdirectory(data)
# add_subdirectory(data)
# extra applications
if(BUILD_opencv_apps)

View File

@ -53,8 +53,6 @@ macro(ocv_add_app directory)
endif()
endmacro()
ocv_add_app(annotation)
ocv_add_app(visualisation)
ocv_add_app(interactive-calibration)
ocv_add_app(version)
ocv_add_app(model-diagnostics)

View File

@ -1,3 +0,0 @@
ocv_add_application(opencv_annotation
MODULES opencv_core opencv_highgui opencv_imgproc opencv_imgcodecs opencv_videoio
SRCS opencv_annotation.cpp)

View File

@ -1,317 +0,0 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
////////////////////////////////////////////////////////////////////////////////////////
/*****************************************************************************************************
USAGE:
./opencv_annotation -images <folder location> -annotations <output file>
Created by: Puttemans Steven - February 2015
Adapted by: Puttemans Steven - April 2016 - Vectorize the process to enable better processing
+ early leave and store by pressing an ESC key
+ enable delete `d` button, to remove last annotation
*****************************************************************************************************/
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/imgproc.hpp>
#include <fstream>
#include <iostream>
#include <map>
using namespace std;
using namespace cv;
// Function prototypes
void on_mouse(int, int, int, int, void*);
vector<Rect> get_annotations(Mat);
// Public parameters
Mat image;
int roi_x0 = 0, roi_y0 = 0, roi_x1 = 0, roi_y1 = 0, num_of_rec = 0;
bool start_draw = false, stop = false;
// Window name for visualisation purposes
const string window_name = "OpenCV Based Annotation Tool";
// FUNCTION : Mouse response for selecting objects in images
// If left button is clicked, start drawing a rectangle as long as mouse moves
// Stop drawing once a new left click is detected by the on_mouse function
void on_mouse(int event, int x, int y, int , void * )
{
// Action when left button is clicked
if(event == EVENT_LBUTTONDOWN)
{
if(!start_draw)
{
roi_x0 = x;
roi_y0 = y;
start_draw = true;
} else {
roi_x1 = x;
roi_y1 = y;
start_draw = false;
}
}
// Action when mouse is moving and drawing is enabled
if((event == EVENT_MOUSEMOVE) && start_draw)
{
// Redraw bounding box for annotation
Mat current_view;
image.copyTo(current_view);
rectangle(current_view, Point(roi_x0,roi_y0), Point(x,y), Scalar(0,0,255));
imshow(window_name, current_view);
}
}
// FUNCTION : returns a vector of Rect objects given an image containing positive object instances
vector<Rect> get_annotations(Mat input_image)
{
vector<Rect> current_annotations;
// Make it possible to exit the annotation process
stop = false;
// Init window interface and couple mouse actions
namedWindow(window_name, WINDOW_AUTOSIZE);
setMouseCallback(window_name, on_mouse);
image = input_image;
imshow(window_name, image);
int key_pressed = 0;
do
{
// Get a temporary image clone
Mat temp_image = input_image.clone();
Rect currentRect(0, 0, 0, 0);
// Keys for processing
// You need to select one for confirming a selection and one to continue to the next image
// Based on the universal ASCII code of the keystroke: http://www.asciitable.com/
// c = 99 add rectangle to current image
// n = 110 save added rectangles and show next image
// d = 100 delete the last annotation made
// <ESC> = 27 exit program
key_pressed = 0xFF & waitKey(0);
switch( key_pressed )
{
case 27:
stop = true;
break;
case 99:
// Draw initiated from top left corner
if(roi_x0<roi_x1 && roi_y0<roi_y1)
{
currentRect.x = roi_x0;
currentRect.y = roi_y0;
currentRect.width = roi_x1-roi_x0;
currentRect.height = roi_y1-roi_y0;
}
// Draw initiated from bottom right corner
if(roi_x0>roi_x1 && roi_y0>roi_y1)
{
currentRect.x = roi_x1;
currentRect.y = roi_y1;
currentRect.width = roi_x0-roi_x1;
currentRect.height = roi_y0-roi_y1;
}
// Draw initiated from top right corner
if(roi_x0>roi_x1 && roi_y0<roi_y1)
{
currentRect.x = roi_x1;
currentRect.y = roi_y0;
currentRect.width = roi_x0-roi_x1;
currentRect.height = roi_y1-roi_y0;
}
// Draw initiated from bottom left corner
if(roi_x0<roi_x1 && roi_y0>roi_y1)
{
currentRect.x = roi_x0;
currentRect.y = roi_y1;
currentRect.width = roi_x1-roi_x0;
currentRect.height = roi_y0-roi_y1;
}
// Draw the rectangle on the canvas
// Add the rectangle to the vector of annotations
current_annotations.push_back(currentRect);
break;
case 100:
// Remove the last annotation
if(current_annotations.size() > 0){
current_annotations.pop_back();
}
break;
default:
// Default case --> do nothing at all
// Other keystrokes can simply be ignored
break;
}
// Check if escape has been pressed
if(stop)
{
break;
}
// Draw all the current rectangles onto the top image and make sure that the global image is linked
for(int i=0; i < (int)current_annotations.size(); i++){
rectangle(temp_image, current_annotations[i], Scalar(0,255,0), 1);
}
image = temp_image;
// Force an explicit redraw of the canvas --> necessary to visualize delete correctly
imshow(window_name, image);
}
// Continue as long as the next image key has not been pressed
while(key_pressed != 110);
// Close down the window
destroyWindow(window_name);
// Return the data
return current_annotations;
}
int main( int argc, const char** argv )
{
// Use the cmdlineparser to process input arguments
CommandLineParser parser(argc, argv,
"{ help h usage ? | | show this message }"
"{ images i | | (required) path to image folder [example - /data/testimages/] }"
"{ annotations a | | (required) path to annotations txt file [example - /data/annotations.txt] }"
"{ maxWindowHeight m | -1 | (optional) images larger in height than this value will be scaled down }"
"{ resizeFactor r | 2 | (optional) factor for scaling down [default = half the size] }"
);
// Read in the input arguments
if (parser.has("help")){
parser.printMessage();
cerr << "TIP: Use absolute paths to avoid any problems with the software!" << endl;
return 0;
}
string image_folder(parser.get<string>("images"));
string annotations_file(parser.get<string>("annotations"));
if (image_folder.empty() || annotations_file.empty()){
parser.printMessage();
cerr << "TIP: Use absolute paths to avoid any problems with the software!" << endl;
return -1;
}
int resizeFactor = parser.get<int>("resizeFactor");
int const maxWindowHeight = parser.get<int>("maxWindowHeight") > 0 ? parser.get<int>("maxWindowHeight") : -1;
// Start by processing the data
// Return the image filenames inside the image folder
map< String, vector<Rect> > annotations;
vector<String> filenames;
String folder(image_folder);
glob(folder, filenames);
// Add key tips on how to use the software when running it
cout << "* mark rectangles with the left mouse button," << endl;
cout << "* press 'c' to accept a selection," << endl;
cout << "* press 'd' to delete the latest selection," << endl;
cout << "* press 'n' to proceed with next image," << endl;
cout << "* press 'esc' to stop." << endl;
// Loop through each image stored in the images folder
// Create and temporarily store the annotations
// At the end write everything to the annotations file
for (size_t i = 0; i < filenames.size(); i++){
// Read in an image
Mat current_image = imread(filenames[i]);
bool const resize_bool = (maxWindowHeight > 0) && (current_image.rows > maxWindowHeight);
// Check if the image is actually read - avoid other files in the folder, because glob() takes them all
// If not then simply skip this iteration
if(current_image.empty()){
continue;
}
if(resize_bool){
resize(current_image, current_image, Size(current_image.cols/resizeFactor, current_image.rows/resizeFactor), 0, 0, INTER_LINEAR_EXACT);
}
// Perform annotations & store the result inside the vectorized structure
// If the image was resized before, then resize the found annotations back to original dimensions
vector<Rect> current_annotations = get_annotations(current_image);
if(resize_bool){
for(int j =0; j < (int)current_annotations.size(); j++){
current_annotations[j].x = current_annotations[j].x * resizeFactor;
current_annotations[j].y = current_annotations[j].y * resizeFactor;
current_annotations[j].width = current_annotations[j].width * resizeFactor;
current_annotations[j].height = current_annotations[j].height * resizeFactor;
}
}
annotations[filenames[i]] = current_annotations;
// Check if the ESC key was hit, then exit earlier then expected
if(stop){
break;
}
}
// When all data is processed, store the data gathered inside the proper file
// This now even gets called when the ESC button was hit to store preliminary results
ofstream output(annotations_file.c_str());
if ( !output.is_open() ){
cerr << "The path for the output file contains an error and could not be opened. Please check again!" << endl;
return 0;
}
// Store the annotations, write to the output file
for(map<String, vector<Rect> >::iterator it = annotations.begin(); it != annotations.end(); it++){
vector<Rect> &anno = it->second;
output << it->first << " " << anno.size();
for(size_t j=0; j < anno.size(); j++){
Rect temp = anno[j];
output << " " << temp.x << " " << temp.y << " " << temp.width << " " << temp.height;
}
output << endl;
}
return 0;
}

View File

@ -1,3 +0,0 @@
ocv_add_application(opencv_visualisation
MODULES opencv_core opencv_highgui opencv_imgproc opencv_videoio opencv_imgcodecs
SRCS opencv_visualisation.cpp)

View File

@ -1,378 +0,0 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
////////////////////////////////////////////////////////////////////////////////////////
/*****************************************************************************************************
Software for visualising cascade classifier models trained by OpenCV and to get a better
understanding of the used features.
USAGE:
./opencv_visualisation --model=<model.xml> --image=<ref.png> --data=<video output folder>
Created by: Puttemans Steven - April 2016
*****************************************************************************************************/
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
using namespace cv;
struct rect_data{
int x;
int y;
int w;
int h;
float weight;
};
static void printLimits(){
cerr << "Limits of the current interface:" << endl;
cerr << " - Only handles cascade classifier models, trained with the opencv_traincascade tool, containing stumps as decision trees [default settings]." << endl;
cerr << " - The image provided needs to be a sample window with the original model dimensions, passed to the --image parameter." << endl;
cerr << " - ONLY handles HAAR and LBP features." << endl;
}
int main( int argc, const char** argv )
{
CommandLineParser parser(argc, argv,
"{ help h usage ? | | show this message }"
"{ image i | | (required) path to reference image }"
"{ model m | | (required) path to cascade xml file }"
"{ data d | | (optional) path to video output folder }"
"{ ext | avi | (optional) output video file extension e.g. avi (default) or mp4 }"
"{ fourcc | XVID | (optional) output video file's 4-character codec e.g. XVID (default) or H264 }"
"{ fps | 15 | (optional) output video file's frames-per-second rate }"
);
// Read in the input arguments
if (parser.has("help")){
parser.printMessage();
printLimits();
return 0;
}
string model(parser.get<string>("model"));
string output_folder(parser.get<string>("data"));
string image_ref = (parser.get<string>("image"));
string fourcc = (parser.get<string>("fourcc"));
int fps = parser.get<int>("fps");
if (model.empty() || image_ref.empty() || fourcc.size()!=4 || fps<1){
parser.printMessage();
printLimits();
return -1;
}
// Value for timing
// You can increase this to have a better visualisation during the generation
int timing = 1;
// Value for cols of storing elements
int cols_prefered = 5;
// Open the XML model
FileStorage fs;
bool model_ok = fs.open(model, FileStorage::READ);
if (!model_ok){
cerr << "the cascade file '" << model << "' could not be loaded." << endl;
return -1;
}
// Get a the required information
// First decide which feature type we are using
FileNode cascade = fs["cascade"];
string feature_type = cascade["featureType"];
bool haar = false, lbp = false;
if (feature_type.compare("HAAR") == 0){
haar = true;
}
if (feature_type.compare("LBP") == 0){
lbp = true;
}
if ( feature_type.compare("HAAR") != 0 && feature_type.compare("LBP")){
cerr << "The model is not an HAAR or LBP feature based model!" << endl;
cerr << "Please select a model that can be visualized by the software." << endl;
return -1;
}
// We make a visualisation mask - which increases the window to make it at least a bit more visible
int resize_factor = 10;
int resize_storage_factor = 10;
Mat reference_image = imread(image_ref, IMREAD_GRAYSCALE );
if (reference_image.empty()){
cerr << "the reference image '" << image_ref << "'' could not be loaded." << endl;
return -1;
}
Mat visualization;
resize(reference_image, visualization, Size(reference_image.cols * resize_factor, reference_image.rows * resize_factor), 0, 0, INTER_LINEAR_EXACT);
// First recover for each stage the number of weak features and their index
// Important since it is NOT sequential when using LBP features
vector< vector<int> > stage_features;
FileNode stages = cascade["stages"];
FileNodeIterator it_stages = stages.begin(), it_stages_end = stages.end();
int idx = 0;
for( ; it_stages != it_stages_end; it_stages++, idx++ ){
vector<int> current_feature_indexes;
FileNode weak_classifiers = (*it_stages)["weakClassifiers"];
FileNodeIterator it_weak = weak_classifiers.begin(), it_weak_end = weak_classifiers.end();
vector<int> values;
for(int idy = 0; it_weak != it_weak_end; it_weak++, idy++ ){
(*it_weak)["internalNodes"] >> values;
current_feature_indexes.push_back( (int)values[2] );
}
stage_features.push_back(current_feature_indexes);
}
// If the output option has been chosen than we will store a combined image plane for
// each stage, containing all weak classifiers for that stage.
bool draw_planes = false;
stringstream output_video;
output_video << output_folder << "model_visualization." << parser.get<string>("ext");
VideoWriter result_video;
if( output_folder.compare("") != 0 ){
draw_planes = true;
result_video.open(output_video.str(), VideoWriter::fourcc(fourcc[0],fourcc[1],fourcc[2],fourcc[3]), fps, visualization.size(), false);
if (!result_video.isOpened()){
cerr << "the output video '" << output_video.str() << "' could not be opened."
<< " fourcc=" << fourcc
<< " fps=" << fps
<< " frameSize=" << visualization.size()
<< endl;
return -1;
}
}
if(haar){
// Grab the corresponding features dimensions and weights
FileNode features = cascade["features"];
vector< vector< rect_data > > feature_data;
FileNodeIterator it_features = features.begin(), it_features_end = features.end();
for(int idf = 0; it_features != it_features_end; it_features++, idf++ ){
vector< rect_data > current_feature_rectangles;
FileNode rectangles = (*it_features)["rects"];
int nrects = (int)rectangles.size();
for(int k = 0; k < nrects; k++){
rect_data current_data;
FileNode single_rect = rectangles[k];
current_data.x = (int)single_rect[0];
current_data.y = (int)single_rect[1];
current_data.w = (int)single_rect[2];
current_data.h = (int)single_rect[3];
current_data.weight = (float)single_rect[4];
current_feature_rectangles.push_back(current_data);
}
feature_data.push_back(current_feature_rectangles);
}
// Loop over each possible feature on its index, visualise on the mask and wait a bit,
// then continue to the next feature.
// If visualisations should be stored then do the in between calculations
Mat image_plane;
Mat metadata = Mat::zeros(150, 1000, CV_8UC1);
vector< rect_data > current_rects;
for(int sid = 0; sid < (int)stage_features.size(); sid ++){
if(draw_planes){
int features_nmbr = (int)stage_features[sid].size();
int cols = cols_prefered;
int rows = features_nmbr / cols;
if( (features_nmbr % cols) > 0){
rows++;
}
image_plane = Mat::zeros(reference_image.rows * resize_storage_factor * rows, reference_image.cols * resize_storage_factor * cols, CV_8UC1);
}
for(int fid = 0; fid < (int)stage_features[sid].size(); fid++){
stringstream meta1, meta2;
meta1 << "Stage " << sid << " / Feature " << fid;
meta2 << "Rectangles: ";
Mat temp_window = visualization.clone();
Mat temp_metadata = metadata.clone();
int current_feature_index = stage_features[sid][fid];
current_rects = feature_data[current_feature_index];
Mat single_feature = reference_image.clone();
resize(single_feature, single_feature, Size(), resize_storage_factor, resize_storage_factor, INTER_LINEAR_EXACT);
for(int i = 0; i < (int)current_rects.size(); i++){
rect_data local = current_rects[i];
if(draw_planes){
if(local.weight >= 0){
rectangle(single_feature, Rect(local.x * resize_storage_factor, local.y * resize_storage_factor, local.w * resize_storage_factor, local.h * resize_storage_factor), Scalar(0), FILLED);
}else{
rectangle(single_feature, Rect(local.x * resize_storage_factor, local.y * resize_storage_factor, local.w * resize_storage_factor, local.h * resize_storage_factor), Scalar(255), FILLED);
}
}
Rect part(local.x * resize_factor, local.y * resize_factor, local.w * resize_factor, local.h * resize_factor);
meta2 << part << " (w " << local.weight << ") ";
if(local.weight >= 0){
rectangle(temp_window, part, Scalar(0), FILLED);
}else{
rectangle(temp_window, part, Scalar(255), FILLED);
}
}
imshow("features", temp_window);
putText(temp_window, meta1.str(), Point(15,15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
result_video.write(temp_window);
// Copy the feature image if needed
if(draw_planes){
single_feature.copyTo(image_plane(Rect(0 + (fid%cols_prefered)*single_feature.cols, 0 + (fid/cols_prefered) * single_feature.rows, single_feature.cols, single_feature.rows)));
}
putText(temp_metadata, meta1.str(), Point(15,15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
putText(temp_metadata, meta2.str(), Point(15,40), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
imshow("metadata", temp_metadata);
waitKey(timing);
}
//Store the stage image if needed
if(draw_planes){
stringstream save_location;
save_location << output_folder << "stage_" << sid << ".png";
imwrite(save_location.str(), image_plane);
}
}
}
if(lbp){
// Grab the corresponding features dimensions and weights
FileNode features = cascade["features"];
vector<Rect> feature_data;
FileNodeIterator it_features = features.begin(), it_features_end = features.end();
for(int idf = 0; it_features != it_features_end; it_features++, idf++ ){
FileNode rectangle = (*it_features)["rect"];
Rect current_feature ((int)rectangle[0], (int)rectangle[1], (int)rectangle[2], (int)rectangle[3]);
feature_data.push_back(current_feature);
}
// Loop over each possible feature on its index, visualise on the mask and wait a bit,
// then continue to the next feature.
Mat image_plane;
Mat metadata = Mat::zeros(150, 1000, CV_8UC1);
for(int sid = 0; sid < (int)stage_features.size(); sid ++){
if(draw_planes){
int features_nmbr = (int)stage_features[sid].size();
int cols = cols_prefered;
int rows = features_nmbr / cols;
if( (features_nmbr % cols) > 0){
rows++;
}
image_plane = Mat::zeros(reference_image.rows * resize_storage_factor * rows, reference_image.cols * resize_storage_factor * cols, CV_8UC1);
}
for(int fid = 0; fid < (int)stage_features[sid].size(); fid++){
stringstream meta1, meta2;
meta1 << "Stage " << sid << " / Feature " << fid;
meta2 << "Rectangle: ";
Mat temp_window = visualization.clone();
Mat temp_metadata = metadata.clone();
int current_feature_index = stage_features[sid][fid];
Rect current_rect = feature_data[current_feature_index];
Mat single_feature = reference_image.clone();
resize(single_feature, single_feature, Size(), resize_storage_factor, resize_storage_factor, INTER_LINEAR_EXACT);
// VISUALISATION
// The rectangle is the top left one of a 3x3 block LBP constructor
Rect resized(current_rect.x * resize_factor, current_rect.y * resize_factor, current_rect.width * resize_factor, current_rect.height * resize_factor);
meta2 << resized;
// Top left
rectangle(temp_window, resized, Scalar(255), 1);
// Top middle
rectangle(temp_window, Rect(resized.x + resized.width, resized.y, resized.width, resized.height), Scalar(255), 1);
// Top right
rectangle(temp_window, Rect(resized.x + 2*resized.width, resized.y, resized.width, resized.height), Scalar(255), 1);
// Middle left
rectangle(temp_window, Rect(resized.x, resized.y + resized.height, resized.width, resized.height), Scalar(255), 1);
// Middle middle
rectangle(temp_window, Rect(resized.x + resized.width, resized.y + resized.height, resized.width, resized.height), Scalar(255), FILLED);
// Middle right
rectangle(temp_window, Rect(resized.x + 2*resized.width, resized.y + resized.height, resized.width, resized.height), Scalar(255), 1);
// Bottom left
rectangle(temp_window, Rect(resized.x, resized.y + 2*resized.height, resized.width, resized.height), Scalar(255), 1);
// Bottom middle
rectangle(temp_window, Rect(resized.x + resized.width, resized.y + 2*resized.height, resized.width, resized.height), Scalar(255), 1);
// Bottom right
rectangle(temp_window, Rect(resized.x + 2*resized.width, resized.y + 2*resized.height, resized.width, resized.height), Scalar(255), 1);
if(draw_planes){
Rect resized_inner(current_rect.x * resize_storage_factor, current_rect.y * resize_storage_factor, current_rect.width * resize_storage_factor, current_rect.height * resize_storage_factor);
// Top left
rectangle(single_feature, resized_inner, Scalar(255), 1);
// Top middle
rectangle(single_feature, Rect(resized_inner.x + resized_inner.width, resized_inner.y, resized_inner.width, resized_inner.height), Scalar(255), 1);
// Top right
rectangle(single_feature, Rect(resized_inner.x + 2*resized_inner.width, resized_inner.y, resized_inner.width, resized_inner.height), Scalar(255), 1);
// Middle left
rectangle(single_feature, Rect(resized_inner.x, resized_inner.y + resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), 1);
// Middle middle
rectangle(single_feature, Rect(resized_inner.x + resized_inner.width, resized_inner.y + resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), FILLED);
// Middle right
rectangle(single_feature, Rect(resized_inner.x + 2*resized_inner.width, resized_inner.y + resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), 1);
// Bottom left
rectangle(single_feature, Rect(resized_inner.x, resized_inner.y + 2*resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), 1);
// Bottom middle
rectangle(single_feature, Rect(resized_inner.x + resized_inner.width, resized_inner.y + 2*resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), 1);
// Bottom right
rectangle(single_feature, Rect(resized_inner.x + 2*resized_inner.width, resized_inner.y + 2*resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), 1);
single_feature.copyTo(image_plane(Rect(0 + (fid%cols_prefered)*single_feature.cols, 0 + (fid/cols_prefered) * single_feature.rows, single_feature.cols, single_feature.rows)));
}
putText(temp_metadata, meta1.str(), Point(15,15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
putText(temp_metadata, meta2.str(), Point(15,40), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
imshow("metadata", temp_metadata);
imshow("features", temp_window);
putText(temp_window, meta1.str(), Point(15,15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
result_video.write(temp_window);
waitKey(timing);
}
//Store the stage image if needed
if(draw_planes){
stringstream save_location;
save_location << output_folder << "stage_" << sid << ".png";
imwrite(save_location.str(), image_plane);
}
}
}
return 0;
}

View File

@ -1,9 +0,0 @@
file(GLOB HAAR_CASCADES haarcascades/*.xml)
file(GLOB LBP_CASCADES lbpcascades/*.xml)
install(FILES ${HAAR_CASCADES} DESTINATION ${OPENCV_OTHER_INSTALL_PATH}/haarcascades COMPONENT libs)
install(FILES ${LBP_CASCADES} DESTINATION ${OPENCV_OTHER_INSTALL_PATH}/lbpcascades COMPONENT libs)
if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH)
install(DIRECTORY "${OPENCV_TEST_DATA_PATH}/" DESTINATION "${OPENCV_TEST_DATA_INSTALL_PATH}" COMPONENT "tests")
endif()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
This folder contains various data that is used by cv libraries and/or demo applications.
----------------------------------------------------------------------------------------
haarcascades - the folder contains trained classifiers for detecting objects
of a particular type, e.g. faces (frontal, profile), pedestrians etc.
Some of the classifiers have a special license - please,
look into the files for details.

View File

@ -255,10 +255,10 @@ if(DOXYGEN_FOUND)
endif()
# copy haar cascade files
set(haar_cascade_files "")
set(data_harrcascades_path "${OpenCV_SOURCE_DIR}/data/haarcascades/")
list(APPEND js_tutorials_assets_deps "${data_harrcascades_path}/haarcascade_frontalface_default.xml" "${data_harrcascades_path}/haarcascade_eye.xml")
list(APPEND js_assets "${data_harrcascades_path}/haarcascade_frontalface_default.xml" "${data_harrcascades_path}/haarcascade_eye.xml")
# set(haar_cascade_files "")
# set(data_harrcascades_path "${OpenCV_SOURCE_DIR}/data/haarcascades/")
# list(APPEND js_tutorials_assets_deps "${data_harrcascades_path}/haarcascade_frontalface_default.xml" "${data_harrcascades_path}/haarcascade_eye.xml")
# list(APPEND js_assets "${data_harrcascades_path}/haarcascade_frontalface_default.xml" "${data_harrcascades_path}/haarcascade_eye.xml")
foreach(f ${js_assets})
get_filename_component(fname "${f}" NAME)

View File

@ -1,107 +0,0 @@
Face Detection using Haar Cascades {#tutorial_js_face_detection}
==================================
Goal
----
- learn the basics of face detection using Haar Feature-based Cascade Classifiers
- extend the same for eye detection etc.
Basics
------
Object Detection using Haar feature-based cascade classifiers is an effective method proposed by Paul Viola and Michael Jones in the 2001 paper, "Rapid Object Detection using a
Boosted Cascade of Simple Features". It is a machine learning based approach in which a cascade
function is trained from a lot of positive and negative images. It is then used to detect objects in
other images.
Here we will work with face detection. Initially, the algorithm needs a lot of positive images
(images of faces) and negative images (images without faces) to train the classifier. Then we need
to extract features from it. For this, Haar features shown in below image are used. They are just
like our convolutional kernel. Each feature is a single value obtained by subtracting the sum of pixels
under the white rectangle from the sum of pixels under the black rectangle.
![image](images/haar_features.jpg)
Now all possible sizes and locations of each kernel are used to calculate plenty of features. For each
feature calculation, we need to find the sum of the pixels under the white and black rectangles. To solve this,
they introduced the integral images. It simplifies calculation of the sum of the pixels, how large may be
the number of pixels, to an operation involving just four pixels.
But among all these features we calculated, most of them are irrelevant. For example, consider the
image below. Top row shows two good features. The first feature selected seems to focus on the
property that the region of the eyes is often darker than the region of the nose and cheeks. The
second feature selected relies on the property that the eyes are darker than the bridge of the nose.
But the same windows applying on cheeks or any other place is irrelevant. So how do we select the
best features out of 160000+ features? It is achieved by **Adaboost**.
![image](images/haar.png)
For this, we apply each and every feature on all the training images. For each feature, it finds the
best threshold which will classify the faces to positive and negative. But obviously, there will be
errors or misclassifications. We select the features with minimum error rate, which means they are
the features that best classifies the face and non-face images. (The process is not as simple as
this. Each image is given an equal weight in the beginning. After each classification, weights of
misclassified images are increased. Then again same process is done. New error rates are calculated.
Also new weights. The process is continued until required accuracy or error rate is achieved or
required number of features are found).
Final classifier is a weighted sum of these weak classifiers. It is called weak because it alone
can't classify the image, but together with others forms a strong classifier. The paper says even
200 features provide detection with 95% accuracy. Their final setup had around 6000 features.
(Imagine a reduction from 160000+ features to 6000 features. That is a big gain).
So now you take an image. Take each 24x24 window. Apply 6000 features to it. Check if it is face or
not. Wow.. Wow.. Isn't it a little inefficient and time consuming? Yes, it is. Authors have a good
solution for that.
In an image, most of the image region is non-face region. So it is a better idea to have a simple
method to check if a window is not a face region. If it is not, discard it in a single shot. Don't
process it again. Instead focus on region where there can be a face. This way, we can find more time
to check a possible face region.
For this they introduced the concept of **Cascade of Classifiers**. Instead of applying all the 6000
features on a window, group the features into different stages of classifiers and apply one-by-one.
(Normally first few stages will contain very less number of features). If a window fails the first
stage, discard it. We don't consider remaining features on it. If it passes, apply the second stage
of features and continue the process. The window which passes all stages is a face region. How is
the plan !!!
Authors' detector had 6000+ features with 38 stages with 1, 10, 25, 25 and 50 features in first five
stages. (Two features in the above image is actually obtained as the best two features from
Adaboost). According to authors, on an average, 10 features out of 6000+ are evaluated per
sub-window.
So this is a simple intuitive explanation of how Viola-Jones face detection works. Read paper for
more details.
Haar-cascade Detection in OpenCV
--------------------------------
Here we will deal with detection. OpenCV already contains many pre-trained classifiers for face,
eyes, smile etc. Those XML files are stored in opencv/data/haarcascades/ folder. Let's create a face
and eye detector with OpenCV.
We use the function: **detectMultiScale (image, objects, scaleFactor = 1.1, minNeighbors = 3, flags = 0, minSize = new cv.Size(0, 0), maxSize = new cv.Size(0, 0))**
@param image matrix of the type CV_8U containing an image where objects are detected.
@param objects vector of rectangles where each rectangle contains the detected object. The rectangles may be partially outside the original image.
@param scaleFactor parameter specifying how much the image size is reduced at each image scale.
@param minNeighbors parameter specifying how many neighbors each candidate rectangle should have to retain it.
@param flags parameter with the same meaning for an old cascade as in the function cvHaarDetectObjects. It is not used for a new cascade.
@param minSize minimum possible object size. Objects smaller than this are ignored.
@param maxSize maximum possible object size. Objects larger than this are ignored. If maxSize == minSize model is evaluated on single scale.
@note Don't forget to delete CascadeClassifier and RectVector!
Try it
------
Try this demo using the code above. Canvas elements named haarCascadeDetectionCanvasInput and haarCascadeDetectionCanvasOutput have been prepared. Choose an image and
click `Try it` to see the result. You can change the code in the textbox to investigate more.
\htmlonly
<iframe src="../../js_face_detection.html" width="100%"
onload="this.style.height=this.contentDocument.body.scrollHeight +'px';">
</iframe>
\endhtmlonly

View File

@ -1,15 +0,0 @@
Face Detection in Video Capture {#tutorial_js_face_detection_camera}
==================================
Goal
----
- learn how to detect faces in video capture.
@note If you don't know how to capture video from camera, please review @ref tutorial_js_video_display.
\htmlonly
<iframe src="../../js_face_detection_camera.html" width="100%"
onload="this.style.height=this.contentDocument.body.scrollHeight +'px';">
</iframe>
\endhtmlonly

View File

@ -1,11 +0,0 @@
Object Detection {#tutorial_js_table_of_contents_objdetect}
================
- @subpage tutorial_js_face_detection
Face detection
using haar-cascades
- @subpage tutorial_js_face_detection_camera
Face Detection in Video Capture

View File

@ -22,11 +22,6 @@ OpenCV.js Tutorials {#tutorial_js_root}
In this section you
will learn different techniques to work with videos like object tracking etc.
- @subpage tutorial_js_table_of_contents_objdetect
In this section you
will object detection techniques like face detection etc.
- @subpage tutorial_js_table_of_contents_dnn
These tutorials show how to use dnn module in JavaScript

View File

@ -623,15 +623,6 @@
volume = {5},
pages = {1530-1536}
}
@inproceedings{Lienhart02,
author = {Lienhart, Rainer and Maydt, Jochen},
title = {An extended set of haar-like features for rapid object detection},
booktitle = {Image Processing. 2002. Proceedings. 2002 International Conference on},
year = {2002},
pages = {I--900},
volume = {1},
publisher = {IEEE}
}
@article{Lowe04,
author = {Lowe, David G.},
title = {Distinctive Image Features from Scale-Invariant Keypoints},
@ -1042,25 +1033,6 @@
number = {3},
publisher = {ACM}
}
@inproceedings{Viola01,
author = {Viola, Paul and Jones, Michael J.},
title = {Rapid object detection using a boosted cascade of simple features},
booktitle = {Computer Vision and Pattern Recognition, 2001. CVPR 2001. Proceedings of the 2001 IEEE Computer Society Conference on},
year = {2001},
pages = {I--511},
volume = {1},
publisher = {IEEE}
}
@article{Viola04,
author = {Viola, Paul and Jones, Michael J.},
title = {Robust real-time face detection},
journal = {International Journal of Computer Vision},
year = {2004},
volume = {57},
number = {2},
pages = {137--154},
publisher = {Kluwer Academic Publishers}
}
@inproceedings{WJ10,
author = {Xu, Wei and Mulligan, Jane},
title = {Performance evaluation of color correction approaches for automatic multi-view image and video stitching},
@ -1159,14 +1131,6 @@
year = {2013},
publisher = {Springer}
}
@incollection{Liao2007,
title = {Learning multi-scale block local binary patterns for face recognition},
author = {Liao, Shengcai and Zhu, Xiangxin and Lei, Zhen and Zhang, Lun and Li, Stan Z},
booktitle = {Advances in Biometrics},
pages = {828--837},
year = {2007},
publisher = {Springer}
}
@incollection{nister2008linear,
title = {Linear time maximally stable extremal regions},
author = {Nist{\'e}r, David and Stew{\'e}nius, Henrik},

View File

@ -1,4 +0,0 @@
Face Detection using Haar Cascades {#tutorial_py_face_detection}
==================================
Tutorial content has been moved: @ref tutorial_cascade_classifier

View File

@ -48,7 +48,7 @@ OpenCV-Python Tutorials {#tutorial_py_root}
- @ref tutorial_table_of_content_objdetect
In this section you
will learn object detection techniques like face detection etc.
will learn object detection techniques.
- @subpage tutorial_py_table_of_contents_bindings

View File

@ -259,10 +259,10 @@ Next, create the directory `src/main/resources` and download this Lena image int
Make sure it's called `"lena.png"`. Items in the resources directory are available to the Java
application at runtime.
Next, copy `lbpcascade_frontalface.xml` from `opencv/data/lbpcascades/` into the `resources`
Next, copy `lbpcascade_frontalface.xml` from `opencv_contrib/modules/xobjdetect/data/lbpcascades/` into the `resources`
directory:
@code{.bash}
cp <opencv_dir>/data/lbpcascades/lbpcascade_frontalface.xml src/main/resources/
cp <xobjdetect_dir>/data/lbpcascades/lbpcascade_frontalface.xml src/main/resources/
@endcode
Now modify src/main/java/HelloOpenCV.java so it contains the following Java code:
@code{.java}
@ -273,7 +273,7 @@ import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.xobjdetect.CascadeClassifier;
//
// Detects faces in an image, draws boxes around them, and writes the results

View File

@ -2,6 +2,8 @@ Detection of ArUco boards {#tutorial_aruco_board_detection}
=========================
@prev_tutorial{tutorial_aruco_detection}
@next_tutorial{tutorial_barcode_detect_and_decode}
| | |
| -: | :- |

View File

@ -3,8 +3,7 @@ Barcode Recognition {#tutorial_barcode_detect_and_decode}
@tableofcontents
@prev_tutorial{tutorial_cascade_classifier}
@next_tutorial{tutorial_introduction_to_pca}
@prev_tutorial{tutorial_aruco_board_detection}
| | |
| -: | :- |

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -3,3 +3,4 @@ Object Detection (objdetect module) {#tutorial_table_of_content_objdetect}
- @subpage tutorial_aruco_detection
- @subpage tutorial_aruco_board_detection
- @subpage tutorial_barcode_detect_and_decode

View File

@ -1,148 +0,0 @@
Cascade Classifier {#tutorial_cascade_classifier}
==================
@tableofcontents
@prev_tutorial{tutorial_optical_flow}
@next_tutorial{tutorial_barcode_detect_and_decode}
| | |
| -: | :- |
| Original author | Ana Huamán |
| Compatibility | OpenCV >= 3.0 |
Goal
----
In this tutorial,
- We will learn how the Haar cascade object detection works.
- We will see the basics of face detection and eye detection using the Haar Feature-based Cascade Classifiers
- We will use the @ref cv::CascadeClassifier class to detect objects in a video stream. Particularly, we
will use the functions:
- @ref cv::CascadeClassifier::load to load a .xml classifier file. It can be either a Haar or a LBP classifier
- @ref cv::CascadeClassifier::detectMultiScale to perform the detection.
Theory
------
Object Detection using Haar feature-based cascade classifiers is an effective object detection
method proposed by Paul Viola and Michael Jones in their paper, "Rapid Object Detection using a
Boosted Cascade of Simple Features" in 2001. It is a machine learning based approach where a cascade
function is trained from a lot of positive and negative images. It is then used to detect objects in
other images.
Here we will work with face detection. Initially, the algorithm needs a lot of positive images
(images of faces) and negative images (images without faces) to train the classifier. Then we need
to extract features from it. For this, Haar features shown in the below image are used. They are just
like our convolutional kernel. Each feature is a single value obtained by subtracting sum of pixels
under the white rectangle from sum of pixels under the black rectangle.
![image](images/haar_features.jpg)
Now, all possible sizes and locations of each kernel are used to calculate lots of features. (Just
imagine how much computation it needs? Even a 24x24 window results over 160000 features). For each
feature calculation, we need to find the sum of the pixels under white and black rectangles. To solve
this, they introduced the integral image. However large your image, it reduces the calculations for a
given pixel to an operation involving just four pixels. Nice, isn't it? It makes things super-fast.
But among all these features we calculated, most of them are irrelevant. For example, consider the
image below. The top row shows two good features. The first feature selected seems to focus on the
property that the region of the eyes is often darker than the region of the nose and cheeks. The
second feature selected relies on the property that the eyes are darker than the bridge of the nose.
But the same windows applied to cheeks or any other place is irrelevant. So how do we select the
best features out of 160000+ features? It is achieved by **Adaboost**.
![image](images/haar.png)
For this, we apply each and every feature on all the training images. For each feature, it finds the
best threshold which will classify the faces to positive and negative. Obviously, there will be
errors or misclassifications. We select the features with minimum error rate, which means they are
the features that most accurately classify the face and non-face images. (The process is not as simple as
this. Each image is given an equal weight in the beginning. After each classification, weights of
misclassified images are increased. Then the same process is done. New error rates are calculated.
Also new weights. The process is continued until the required accuracy or error rate is achieved or
the required number of features are found).
The final classifier is a weighted sum of these weak classifiers. It is called weak because it alone
can't classify the image, but together with others forms a strong classifier. The paper says even
200 features provide detection with 95% accuracy. Their final setup had around 6000 features.
(Imagine a reduction from 160000+ features to 6000 features. That is a big gain).
So now you take an image. Take each 24x24 window. Apply 6000 features to it. Check if it is face or
not. Wow.. Isn't it a little inefficient and time consuming? Yes, it is. The authors have a good
solution for that.
In an image, most of the image is non-face region. So it is a better idea to have a simple
method to check if a window is not a face region. If it is not, discard it in a single shot, and don't
process it again. Instead, focus on regions where there can be a face. This way, we spend more time
checking possible face regions.
For this they introduced the concept of **Cascade of Classifiers**. Instead of applying all 6000
features on a window, the features are grouped into different stages of classifiers and applied one-by-one.
(Normally the first few stages will contain very many fewer features). If a window fails the first
stage, discard it. We don't consider the remaining features on it. If it passes, apply the second stage
of features and continue the process. The window which passes all stages is a face region. How is
that plan!
The authors' detector had 6000+ features with 38 stages with 1, 10, 25, 25 and 50 features in the first five
stages. (The two features in the above image are actually obtained as the best two features from
Adaboost). According to the authors, on average 10 features out of 6000+ are evaluated per
sub-window.
So this is a simple intuitive explanation of how Viola-Jones face detection works. Read the paper for
more details or check out the references in the Additional Resources section.
Haar-cascade Detection in OpenCV
--------------------------------
OpenCV provides pretrained models that can be read using the @ref cv::CascadeClassifier::load method.
These models are located in the data folder in the OpenCV installation or can be found [here](https://github.com/opencv/opencv/tree/5.x/data).
The following code example will use pretrained Haar cascade models to detect faces and eyes in an image.
First, a @ref cv::CascadeClassifier is created and the necessary XML file is loaded using the @ref cv::CascadeClassifier::load method.
Afterwards, the detection is done using the @ref cv::CascadeClassifier::detectMultiScale method, which returns boundary rectangles for the detected faces or eyes.
@add_toggle_cpp
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/5.x/samples/cpp/tutorial_code/objectDetection/objectDetection.cpp)
@include samples/cpp/tutorial_code/objectDetection/objectDetection.cpp
@end_toggle
@add_toggle_java
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/5.x/samples/java/tutorial_code/objectDetection/cascade_classifier/ObjectDetectionDemo.java)
@include samples/java/tutorial_code/objectDetection/cascade_classifier/ObjectDetectionDemo.java
@end_toggle
@add_toggle_python
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/5.x/samples/python/tutorial_code/objectDetection/cascade_classifier/objectDetection.py)
@include samples/python/tutorial_code/objectDetection/cascade_classifier/objectDetection.py
@end_toggle
Result
------
-# Here is the result of running the code above and using as input the video stream of a built-in
webcam:
![](images/Cascade_Classifier_Tutorial_Result_Haar.jpg)
Be sure the program will find the path of files *haarcascade_frontalface_alt.xml* and
*haarcascade_eye_tree_eyeglasses.xml*. They are located in
*opencv/data/haarcascades*
-# This is the result of using the file *lbpcascade_frontalface.xml* (LBP trained) for the face
detection. For the eyes we keep using the file used in the tutorial.
![](images/Cascade_Classifier_Tutorial_Result_LBP.jpg)
Additional Resources
--------------------
-# Paul Viola and Michael J. Jones. Robust real-time face detection. International Journal of Computer Vision, 57(2):137154, 2004. @cite Viola04
-# Rainer Lienhart and Jochen Maydt. An extended set of haar-like features for rapid object detection. In Image Processing. 2002. Proceedings. 2002 International Conference on, volume 1, pages I900. IEEE, 2002. @cite Lienhart02
-# Video Lecture on [Face Detection and Tracking](https://www.youtube.com/watch?v=WfdYYNamHZ8)
-# An interesting interview regarding Face Detection by [Adam
Harvey](https://web.archive.org/web/20171204220159/http://www.makematics.com/research/viola-jones/)
-# [OpenCV Face Detection: Visualized](https://vimeo.com/12774628) on Vimeo by Adam Harvey

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 KiB

View File

@ -3,7 +3,7 @@ Introduction to Principal Component Analysis (PCA) {#tutorial_introduction_to_pc
@tableofcontents
@prev_tutorial{tutorial_barcode_detect_and_decode}
@prev_tutorial{tutorial_optical_flow}
| | |
| -: | :- |

View File

@ -4,7 +4,7 @@ Optical Flow {#tutorial_optical_flow}
@tableofcontents
@prev_tutorial{tutorial_meanshift}
@next_tutorial{tutorial_cascade_classifier}
@next_tutorial{tutorial_introduction_to_pca}
Goal
----

View File

@ -1,4 +1,4 @@
Other tutorials (objdetect, photo, stitching, video) {#tutorial_table_of_content_other}
Other tutorials (photo, stitching, video) {#tutorial_table_of_content_other}
========================================================
- photo. @subpage tutorial_hdr_imaging
@ -6,6 +6,4 @@ Other tutorials (objdetect, photo, stitching, video) {#tutorial_table_of_content
- video. @subpage tutorial_background_subtraction
- video. @subpage tutorial_meanshift
- video. @subpage tutorial_optical_flow
- objdetect. @subpage tutorial_cascade_classifier
- objdetect. @subpage tutorial_barcode_detect_and_decode
- ml. @subpage tutorial_introduction_to_pca

View File

@ -10,7 +10,7 @@ OpenCV Tutorials {#tutorial_root}
- @subpage tutorial_table_of_content_features2d - feature detectors, descriptors and matching framework
- @subpage tutorial_table_of_content_dnn - infer neural networks using built-in _dnn_ module
- @subpage tutorial_table_of_content_gapi - graph-based approach to computer vision algorithms building
- @subpage tutorial_table_of_content_other - other modules (objdetect, stitching, video, photo)
- @subpage tutorial_table_of_content_other - other modules (stitching, video, photo)
- @subpage tutorial_table_of_content_ios - running OpenCV on an iDevice
- @subpage tutorial_table_of_content_3d - 3d objects processing and visualisation
@cond CUDA_MODULES

View File

@ -76,9 +76,6 @@
#ifdef HAVE_OPENCV_IMGPROC
#include "opencv2/imgproc.hpp"
#endif
#ifdef HAVE_OPENCV_ML
#include "opencv2/ml.hpp"
#endif
#ifdef HAVE_OPENCV_OBJDETECT
#include "opencv2/objdetect.hpp"
#endif

View File

@ -71,94 +71,9 @@
if (typeof module !== 'undefined' && module.exports) {
// The environment is Node.js
var cv = require('./opencv.js'); // eslint-disable-line no-var
cv.FS_createLazyFile('/', 'haarcascade_frontalface_default.xml', // eslint-disable-line new-cap
'haarcascade_frontalface_default.xml', true, false);
}
QUnit.module('Object Detection', {});
QUnit.test('Cascade classification', function(assert) {
// Group rectangle
{
let rectList = new cv.RectVector();
let weights = new cv.IntVector();
let groupThreshold = 1;
const eps = 0.2;
let rect1 = new cv.Rect(1, 2, 3, 4);
let rect2 = new cv.Rect(1, 4, 2, 3);
rectList.push_back(rect1);
rectList.push_back(rect2);
cv.groupRectangles(rectList, weights, groupThreshold, eps);
rectList.delete();
weights.delete();
}
// CascadeClassifier
{
let classifier = new cv.CascadeClassifier();
const modelPath = '/haarcascade_frontalface_default.xml';
assert.equal(classifier.empty(), true);
classifier.load(modelPath);
assert.equal(classifier.empty(), false);
let image = cv.Mat.eye({height: 10, width: 10}, cv.CV_8UC3);
let objects = new cv.RectVector();
let numDetections = new cv.IntVector();
const scaleFactor = 1.1;
const minNeighbors = 3;
const flags = 0;
const minSize = {height: 0, width: 0};
const maxSize = {height: 10, width: 10};
classifier.detectMultiScale2(image, objects, numDetections, scaleFactor,
minNeighbors, flags, minSize, maxSize);
// test default parameters
classifier.detectMultiScale2(image, objects, numDetections, scaleFactor,
minNeighbors, flags, minSize);
classifier.detectMultiScale2(image, objects, numDetections, scaleFactor,
minNeighbors, flags);
classifier.detectMultiScale2(image, objects, numDetections, scaleFactor,
minNeighbors);
classifier.detectMultiScale2(image, objects, numDetections, scaleFactor);
classifier.delete();
objects.delete();
numDetections.delete();
}
// HOGDescriptor
{
let hog = new cv.HOGDescriptor();
let mat = new cv.Mat({height: 10, width: 10}, cv.CV_8UC1);
let descriptors = new cv.FloatVector();
let locations = new cv.PointVector();
assert.equal(hog.winSize.height, 128);
assert.equal(hog.winSize.width, 64);
assert.equal(hog.nbins, 9);
assert.equal(hog.derivAperture, 1);
assert.equal(hog.winSigma, -1);
assert.equal(hog.histogramNormType, 0);
assert.equal(hog.nlevels, 64);
hog.nlevels = 32;
assert.equal(hog.nlevels, 32);
hog.delete();
mat.delete();
descriptors.delete();
locations.delete();
}
});
QUnit.test('QR code detect and decode', function (assert) {
{
const detector = new cv.QRCodeDetector();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -52,57 +52,6 @@
@defgroup objdetect Object Detection
@{
@defgroup objdetect_cascade_classifier Cascade Classifier for Object Detection
The object detector described below has been initially proposed by Paul Viola @cite Viola01 and
improved by Rainer Lienhart @cite Lienhart02 .
First, a classifier (namely a *cascade of boosted classifiers working with haar-like features*) is
trained with a few hundred sample views of a particular object (i.e., a face or a car), called
positive examples, that are scaled to the same size (say, 20x20), and negative examples - arbitrary
images of the same size.
After a classifier is trained, it can be applied to a region of interest (of the same size as used
during the training) in an input image. The classifier outputs a "1" if the region is likely to show
the object (i.e., face/car), and "0" otherwise. To search for the object in the whole image one can
move the search window across the image and check every location using the classifier. The
classifier is designed so that it can be easily "resized" in order to be able to find the objects of
interest at different sizes, which is more efficient than resizing the image itself. So, to find an
object of an unknown size in the image the scan procedure should be done several times at different
scales.
The word "cascade" in the classifier name means that the resultant classifier consists of several
simpler classifiers (*stages*) that are applied subsequently to a region of interest until at some
stage the candidate is rejected or all the stages are passed. The word "boosted" means that the
classifiers at every stage of the cascade are complex themselves and they are built out of basic
classifiers using one of four different boosting techniques (weighted voting). Currently Discrete
Adaboost, Real Adaboost, Gentle Adaboost and Logitboost are supported. The basic classifiers are
decision-tree classifiers with at least 2 leaves. Haar-like features are the input to the basic
classifiers, and are calculated as described below. The current algorithm uses the following
Haar-like features:
![image](pics/haarfeatures.png)
The feature used in a particular classifier is specified by its shape (1a, 2b etc.), position within
the region of interest and the scale (this scale is not the same as the scale used at the detection
stage, though these two scales are multiplied). For example, in the case of the third line feature
(2c) the response is calculated as the difference between the sum of image pixels under the
rectangle covering the whole feature (including the two white stripes and the black stripe in the
middle) and the sum of the image pixels under the black stripe multiplied by 3 in order to
compensate for the differences in the size of areas. The sums of pixel values over a rectangular
regions are calculated rapidly using integral images (see below and the integral description).
Check @ref tutorial_cascade_classifier "the corresponding tutorial" for more details.
The following reference is for the detection part only. There is a separate application called
opencv_traincascade that can train a cascade of boosted classifiers from a set of samples.
@note In the new C++ interface it is also possible to use LBP (local binary pattern) features in
addition to Haar-like features. .. [Viola01] Paul Viola and Michael J. Jones. Rapid Object Detection
using a Boosted Cascade of Simple Features. IEEE CVPR, 2001. The paper is available online at
<https://github.com/SvHey/thesis/blob/master/Literature/ObjectDetection/violaJones_CVPR2001.pdf>
@defgroup objdetect_hog HOG (Histogram of Oriented Gradients) descriptor and object detector
@defgroup objdetect_barcode Barcode detection and decoding
@defgroup objdetect_qrcode QRCode detection and encoding
@defgroup objdetect_dnn_face DNN-based face detection and recognition
@ -133,564 +82,8 @@
@}
*/
typedef struct CvHaarClassifierCascade CvHaarClassifierCascade;
namespace cv
{
//! @addtogroup objdetect_common
//! @{
///////////////////////////// Object Detection ////////////////////////////
/** @brief This class is used for grouping object candidates detected by Cascade Classifier, HOG etc.
instance of the class is to be passed to cv::partition
*/
class CV_EXPORTS SimilarRects
{
public:
SimilarRects(double _eps) : eps(_eps) {}
inline bool operator()(const Rect& r1, const Rect& r2) const
{
double delta = eps * ((std::min)(r1.width, r2.width) + (std::min)(r1.height, r2.height)) * 0.5;
return std::abs(r1.x - r2.x) <= delta &&
std::abs(r1.y - r2.y) <= delta &&
std::abs(r1.x + r1.width - r2.x - r2.width) <= delta &&
std::abs(r1.y + r1.height - r2.y - r2.height) <= delta;
}
double eps;
};
/** @brief Groups the object candidate rectangles.
@param rectList Input/output vector of rectangles. Output vector includes retained and grouped
rectangles. (The Python list is not modified in place.)
@param groupThreshold Minimum possible number of rectangles minus 1. The threshold is used in a
group of rectangles to retain it.
@param eps Relative difference between sides of the rectangles to merge them into a group.
The function is a wrapper for the generic function partition . It clusters all the input rectangles
using the rectangle equivalence criteria that combines rectangles with similar sizes and similar
locations. The similarity is defined by eps. When eps=0 , no clustering is done at all. If
\f$\texttt{eps}\rightarrow +\inf\f$ , all the rectangles are put in one cluster. Then, the small
clusters containing less than or equal to groupThreshold rectangles are rejected. In each other
cluster, the average rectangle is computed and put into the output rectangle list.
*/
CV_EXPORTS void groupRectangles(std::vector<Rect>& rectList, int groupThreshold, double eps = 0.2);
/** @overload */
CV_EXPORTS_W void groupRectangles(CV_IN_OUT std::vector<Rect>& rectList, CV_OUT std::vector<int>& weights,
int groupThreshold, double eps = 0.2);
/** @overload */
CV_EXPORTS void groupRectangles(std::vector<Rect>& rectList, int groupThreshold,
double eps, std::vector<int>* weights, std::vector<double>* levelWeights );
/** @overload */
CV_EXPORTS void groupRectangles(std::vector<Rect>& rectList, std::vector<int>& rejectLevels,
std::vector<double>& levelWeights, int groupThreshold, double eps = 0.2);
/** @overload */
CV_EXPORTS void groupRectangles_meanshift(std::vector<Rect>& rectList, std::vector<double>& foundWeights,
std::vector<double>& foundScales,
double detectThreshold = 0.0, Size winDetSize = Size(64, 128));
//! @}
//! @addtogroup objdetect_cascade_classifier
//! @{
template<> struct DefaultDeleter<CvHaarClassifierCascade>{ CV_EXPORTS void operator ()(CvHaarClassifierCascade* obj) const; };
enum { CASCADE_DO_CANNY_PRUNING = 1,
CASCADE_SCALE_IMAGE = 2,
CASCADE_FIND_BIGGEST_OBJECT = 4,
CASCADE_DO_ROUGH_SEARCH = 8
};
class CV_EXPORTS_W BaseCascadeClassifier : public Algorithm
{
public:
virtual ~BaseCascadeClassifier();
virtual bool empty() const CV_OVERRIDE = 0;
virtual bool load( const String& filename ) = 0;
virtual void detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& objects,
double scaleFactor,
int minNeighbors, int flags,
Size minSize, Size maxSize ) = 0;
virtual void detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& objects,
CV_OUT std::vector<int>& numDetections,
double scaleFactor,
int minNeighbors, int flags,
Size minSize, Size maxSize ) = 0;
virtual void detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& objects,
CV_OUT std::vector<int>& rejectLevels,
CV_OUT std::vector<double>& levelWeights,
double scaleFactor,
int minNeighbors, int flags,
Size minSize, Size maxSize,
bool outputRejectLevels ) = 0;
virtual bool isOldFormatCascade() const = 0;
virtual Size getOriginalWindowSize() const = 0;
virtual int getFeatureType() const = 0;
virtual void* getOldCascade() = 0;
class CV_EXPORTS MaskGenerator
{
public:
virtual ~MaskGenerator() {}
virtual Mat generateMask(const Mat& src)=0;
virtual void initializeMask(const Mat& /*src*/) { }
};
virtual void setMaskGenerator(const Ptr<MaskGenerator>& maskGenerator) = 0;
virtual Ptr<MaskGenerator> getMaskGenerator() = 0;
};
/** @example samples/cpp/facedetect.cpp
This program demonstrates usage of the Cascade classifier class
\image html Cascade_Classifier_Tutorial_Result_Haar.jpg "Sample screenshot" width=321 height=254
*/
/** @brief Cascade classifier class for object detection.
*/
class CV_EXPORTS_W CascadeClassifier
{
public:
CV_WRAP CascadeClassifier();
/** @brief Loads a classifier from a file.
@param filename Name of the file from which the classifier is loaded.
*/
CV_WRAP CascadeClassifier(const String& filename);
~CascadeClassifier();
/** @brief Checks whether the classifier has been loaded.
*/
CV_WRAP bool empty() const;
/** @brief Loads a classifier from a file.
@param filename Name of the file from which the classifier is loaded. The file may contain an old
HAAR classifier trained by the haartraining application or a new cascade classifier trained by the
traincascade application.
*/
CV_WRAP bool load( const String& filename );
/** @brief Reads a classifier from a FileStorage node.
@note The file may contain a new cascade classifier (trained by the traincascade application) only.
*/
CV_WRAP bool read( const FileNode& node );
/** @brief Detects objects of different sizes in the input image. The detected objects are returned as a list
of rectangles.
@param image Matrix of the type CV_8U containing an image where objects are detected.
@param objects Vector of rectangles where each rectangle contains the detected object, the
rectangles may be partially outside the original image.
@param scaleFactor Parameter specifying how much the image size is reduced at each image scale.
@param minNeighbors Parameter specifying how many neighbors each candidate rectangle should have
to retain it.
@param flags Parameter with the same meaning for an old cascade as in the function
cvHaarDetectObjects. It is not used for a new cascade.
@param minSize Minimum possible object size. Objects smaller than that are ignored.
@param maxSize Maximum possible object size. Objects larger than that are ignored. If `maxSize == minSize` model is evaluated on single scale.
*/
CV_WRAP void detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& objects,
double scaleFactor = 1.1,
int minNeighbors = 3, int flags = 0,
Size minSize = Size(),
Size maxSize = Size() );
/** @overload
@param image Matrix of the type CV_8U containing an image where objects are detected.
@param objects Vector of rectangles where each rectangle contains the detected object, the
rectangles may be partially outside the original image.
@param numDetections Vector of detection numbers for the corresponding objects. An object's number
of detections is the number of neighboring positively classified rectangles that were joined
together to form the object.
@param scaleFactor Parameter specifying how much the image size is reduced at each image scale.
@param minNeighbors Parameter specifying how many neighbors each candidate rectangle should have
to retain it.
@param flags Parameter with the same meaning for an old cascade as in the function
cvHaarDetectObjects. It is not used for a new cascade.
@param minSize Minimum possible object size. Objects smaller than that are ignored.
@param maxSize Maximum possible object size. Objects larger than that are ignored. If `maxSize == minSize` model is evaluated on single scale.
*/
CV_WRAP_AS(detectMultiScale2) void detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& objects,
CV_OUT std::vector<int>& numDetections,
double scaleFactor=1.1,
int minNeighbors=3, int flags=0,
Size minSize=Size(),
Size maxSize=Size() );
/** @overload
This function allows you to retrieve the final stage decision certainty of classification.
For this, one needs to set `outputRejectLevels` on true and provide the `rejectLevels` and `levelWeights` parameter.
For each resulting detection, `levelWeights` will then contain the certainty of classification at the final stage.
This value can then be used to separate strong from weaker classifications.
A code sample on how to use it efficiently can be found below:
@code
Mat img;
vector<double> weights;
vector<int> levels;
vector<Rect> detections;
CascadeClassifier model("/path/to/your/model.xml");
model.detectMultiScale(img, detections, levels, weights, 1.1, 3, 0, Size(), Size(), true);
cerr << "Detection " << detections[0] << " with weight " << weights[0] << endl;
@endcode
*/
CV_WRAP_AS(detectMultiScale3) void detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& objects,
CV_OUT std::vector<int>& rejectLevels,
CV_OUT std::vector<double>& levelWeights,
double scaleFactor = 1.1,
int minNeighbors = 3, int flags = 0,
Size minSize = Size(),
Size maxSize = Size(),
bool outputRejectLevels = false );
CV_WRAP bool isOldFormatCascade() const;
CV_WRAP Size getOriginalWindowSize() const;
CV_WRAP int getFeatureType() const;
void* getOldCascade();
CV_WRAP static bool convert(const String& oldcascade, const String& newcascade);
void setMaskGenerator(const Ptr<BaseCascadeClassifier::MaskGenerator>& maskGenerator);
Ptr<BaseCascadeClassifier::MaskGenerator> getMaskGenerator();
Ptr<BaseCascadeClassifier> cc;
};
CV_EXPORTS Ptr<BaseCascadeClassifier::MaskGenerator> createFaceDetectionMaskGenerator();
//! @}
//! @addtogroup objdetect_hog
//! @{
//////////////// HOG (Histogram-of-Oriented-Gradients) Descriptor and Object Detector //////////////
//! struct for detection region of interest (ROI)
struct DetectionROI
{
//! scale(size) of the bounding box
double scale;
//! set of requested locations to be evaluated
std::vector<cv::Point> locations;
//! vector that will contain confidence values for each location
std::vector<double> confidences;
};
/**@brief Implementation of HOG (Histogram of Oriented Gradients) descriptor and object detector.
the HOG descriptor algorithm introduced by Navneet Dalal and Bill Triggs @cite Dalal2005 .
useful links:
https://hal.inria.fr/inria-00548512/document/
https://en.wikipedia.org/wiki/Histogram_of_oriented_gradients
https://software.intel.com/en-us/ipp-dev-reference-histogram-of-oriented-gradients-hog-descriptor
http://www.learnopencv.com/histogram-of-oriented-gradients
http://www.learnopencv.com/handwritten-digits-classification-an-opencv-c-python-tutorial
*/
class CV_EXPORTS_W HOGDescriptor
{
public:
enum HistogramNormType { L2Hys = 0 //!< Default histogramNormType
};
enum { DEFAULT_NLEVELS = 64 //!< Default nlevels value.
};
enum DescriptorStorageFormat { DESCR_FORMAT_COL_BY_COL, DESCR_FORMAT_ROW_BY_ROW };
/**@brief Creates the HOG descriptor and detector with default parameters.
@param _winSize sets winSize with given value.
@param _blockSize sets blockSize with given value.
@param _blockStride sets blockStride with given value.
@param _cellSize sets cellSize with given value.
@param _nbins sets nbins with given value.
@param _derivAperture sets derivAperture with given value.
@param _winSigma sets winSigma with given value.
@param _histogramNormType sets histogramNormType with given value.
@param _L2HysThreshold sets L2HysThreshold with given value.
@param _gammaCorrection sets gammaCorrection with given value.
@param _nlevels sets nlevels with given value.
@param _signedGradient sets signedGradient with given value.
*/
CV_WRAP HOGDescriptor(Size _winSize = Size(64, 128), Size _blockSize = Size(16, 16), Size _blockStride = Size(8, 8),
Size _cellSize = Size(8, 8), int _nbins = 9, int _derivAperture = 1, double _winSigma = -1,
HOGDescriptor::HistogramNormType _histogramNormType = HOGDescriptor::L2Hys,
double _L2HysThreshold = 0.2, bool _gammaCorrection = true,
int _nlevels = HOGDescriptor::DEFAULT_NLEVELS, bool _signedGradient = false)
: winSize(_winSize), blockSize(_blockSize), blockStride(_blockStride), cellSize(_cellSize),
nbins(_nbins), derivAperture(_derivAperture), winSigma(_winSigma),
histogramNormType(_histogramNormType), L2HysThreshold(_L2HysThreshold),
gammaCorrection(_gammaCorrection), free_coef(-1.f), nlevels(_nlevels), signedGradient(_signedGradient)
{}
/** @overload
Creates the HOG descriptor and detector and loads HOGDescriptor parameters and coefficients for the linear SVM classifier from a file.
@param filename The file name containing HOGDescriptor properties and coefficients for the linear SVM classifier.
*/
CV_WRAP HOGDescriptor(const String& filename)
{
load(filename);
}
/** @overload
@param d the HOGDescriptor which cloned to create a new one.
*/
HOGDescriptor(const HOGDescriptor& d)
{
d.copyTo(*this);
}
/**@brief Default destructor.
*/
virtual ~HOGDescriptor() {}
/**@brief Returns the number of coefficients required for the classification.
*/
CV_WRAP size_t getDescriptorSize() const;
/** @brief Checks if detector size equal to descriptor size.
*/
CV_WRAP bool checkDetectorSize() const;
/** @brief Returns winSigma value
*/
CV_WRAP double getWinSigma() const;
/**@example samples/cpp/peopledetect.cpp
*/
/**@brief Sets coefficients for the linear SVM classifier.
@param svmdetector coefficients for the linear SVM classifier.
*/
CV_WRAP virtual void setSVMDetector(InputArray svmdetector);
/** @brief Reads HOGDescriptor parameters and coefficients for the linear SVM classifier from a file node.
@param fn File node
*/
virtual bool read(FileNode& fn);
/** @brief Stores HOGDescriptor parameters and coefficients for the linear SVM classifier in a file storage.
@param fs File storage
@param objname Object name
*/
virtual void write(FileStorage& fs, const String& objname) const;
/** @brief loads HOGDescriptor parameters and coefficients for the linear SVM classifier from a file
@param filename Name of the file to read.
@param objname The optional name of the node to read (if empty, the first top-level node will be used).
*/
CV_WRAP virtual bool load(const String& filename, const String& objname = String());
/** @brief saves HOGDescriptor parameters and coefficients for the linear SVM classifier to a file
@param filename File name
@param objname Object name
*/
CV_WRAP virtual void save(const String& filename, const String& objname = String()) const;
/** @brief clones the HOGDescriptor
@param c cloned HOGDescriptor
*/
virtual void copyTo(HOGDescriptor& c) const;
/** @brief Computes HOG descriptors of given image.
@param img Matrix of the type CV_8U containing an image where HOG features will be calculated.
@param descriptors Matrix of the type CV_32F
@param winStride Window stride. It must be a multiple of block stride.
@param padding Padding
@param locations Vector of Point
*/
CV_WRAP virtual void compute(InputArray img,
CV_OUT std::vector<float>& descriptors,
Size winStride = Size(), Size padding = Size(),
const std::vector<Point>& locations = std::vector<Point>()) const;
/** @brief Performs object detection without a multi-scale window.
@param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected.
@param foundLocations Vector of point where each point contains left-top corner point of detected object boundaries.
@param weights Vector that will contain confidence values for each detected object.
@param hitThreshold Threshold for the distance between features and SVM classifying plane.
Usually it is 0 and should be specified in the detector coefficients (as the last free coefficient).
But if the free coefficient is omitted (which is allowed), you can specify it manually here.
@param winStride Window stride. It must be a multiple of block stride.
@param padding Padding
@param searchLocations Vector of Point includes set of requested locations to be evaluated.
*/
CV_WRAP virtual void detect(InputArray img, CV_OUT std::vector<Point>& foundLocations,
CV_OUT std::vector<double>& weights,
double hitThreshold = 0, Size winStride = Size(),
Size padding = Size(),
const std::vector<Point>& searchLocations = std::vector<Point>()) const;
/** @brief Performs object detection without a multi-scale window.
@param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected.
@param foundLocations Vector of point where each point contains left-top corner point of detected object boundaries.
@param hitThreshold Threshold for the distance between features and SVM classifying plane.
Usually it is 0 and should be specified in the detector coefficients (as the last free coefficient).
But if the free coefficient is omitted (which is allowed), you can specify it manually here.
@param winStride Window stride. It must be a multiple of block stride.
@param padding Padding
@param searchLocations Vector of Point includes locations to search.
*/
virtual void detect(InputArray img, CV_OUT std::vector<Point>& foundLocations,
double hitThreshold = 0, Size winStride = Size(),
Size padding = Size(),
const std::vector<Point>& searchLocations=std::vector<Point>()) const;
/** @brief Detects objects of different sizes in the input image. The detected objects are returned as a list
of rectangles.
@param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected.
@param foundLocations Vector of rectangles where each rectangle contains the detected object.
@param foundWeights Vector that will contain confidence values for each detected object.
@param hitThreshold Threshold for the distance between features and SVM classifying plane.
Usually it is 0 and should be specified in the detector coefficients (as the last free coefficient).
But if the free coefficient is omitted (which is allowed), you can specify it manually here.
@param winStride Window stride. It must be a multiple of block stride.
@param padding Padding
@param scale Coefficient of the detection window increase.
@param groupThreshold Coefficient to regulate the similarity threshold. When detected, some objects can be covered
by many rectangles. 0 means not to perform grouping.
@param useMeanshiftGrouping indicates grouping algorithm
*/
CV_WRAP virtual void detectMultiScale(InputArray img, CV_OUT std::vector<Rect>& foundLocations,
CV_OUT std::vector<double>& foundWeights, double hitThreshold = 0,
Size winStride = Size(), Size padding = Size(), double scale = 1.05,
double groupThreshold = 2.0, bool useMeanshiftGrouping = false) const;
/** @brief Detects objects of different sizes in the input image. The detected objects are returned as a list
of rectangles.
@param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected.
@param foundLocations Vector of rectangles where each rectangle contains the detected object.
@param hitThreshold Threshold for the distance between features and SVM classifying plane.
Usually it is 0 and should be specified in the detector coefficients (as the last free coefficient).
But if the free coefficient is omitted (which is allowed), you can specify it manually here.
@param winStride Window stride. It must be a multiple of block stride.
@param padding Padding
@param scale Coefficient of the detection window increase.
@param groupThreshold Coefficient to regulate the similarity threshold. When detected, some objects can be covered
by many rectangles. 0 means not to perform grouping.
@param useMeanshiftGrouping indicates grouping algorithm
*/
virtual void detectMultiScale(InputArray img, CV_OUT std::vector<Rect>& foundLocations,
double hitThreshold = 0, Size winStride = Size(),
Size padding = Size(), double scale = 1.05,
double groupThreshold = 2.0, bool useMeanshiftGrouping = false) const;
/** @brief Computes gradients and quantized gradient orientations.
@param img Matrix contains the image to be computed
@param grad Matrix of type CV_32FC2 contains computed gradients
@param angleOfs Matrix of type CV_8UC2 contains quantized gradient orientations
@param paddingTL Padding from top-left
@param paddingBR Padding from bottom-right
*/
CV_WRAP virtual void computeGradient(InputArray img, InputOutputArray grad, InputOutputArray angleOfs,
Size paddingTL = Size(), Size paddingBR = Size()) const;
/** @brief Returns coefficients of the classifier trained for people detection (for 64x128 windows).
*/
CV_WRAP static std::vector<float> getDefaultPeopleDetector();
/**@example samples/tapi/hog.cpp
*/
/** @brief Returns coefficients of the classifier trained for people detection (for 48x96 windows).
*/
CV_WRAP static std::vector<float> getDaimlerPeopleDetector();
//! Detection window size. Align to block size and block stride. Default value is Size(64,128).
CV_PROP Size winSize;
//! Block size in pixels. Align to cell size. Default value is Size(16,16).
CV_PROP Size blockSize;
//! Block stride. It must be a multiple of cell size. Default value is Size(8,8).
CV_PROP Size blockStride;
//! Cell size. Default value is Size(8,8).
CV_PROP Size cellSize;
//! Number of bins used in the calculation of histogram of gradients. Default value is 9.
CV_PROP int nbins;
//! not documented
CV_PROP int derivAperture;
//! Gaussian smoothing window parameter.
CV_PROP double winSigma;
//! histogramNormType
CV_PROP HOGDescriptor::HistogramNormType histogramNormType;
//! L2-Hys normalization method shrinkage.
CV_PROP double L2HysThreshold;
//! Flag to specify whether the gamma correction preprocessing is required or not.
CV_PROP bool gammaCorrection;
//! coefficients for the linear SVM classifier.
CV_PROP std::vector<float> svmDetector;
//! coefficients for the linear SVM classifier used when OpenCL is enabled
UMat oclSvmDetector;
//! not documented
float free_coef;
//! Maximum number of detection window increases. Default value is 64
CV_PROP int nlevels;
//! Indicates signed gradient will be used or not
CV_PROP bool signedGradient;
/** @brief evaluate specified ROI and return confidence value for each location
@param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected.
@param locations Vector of Point
@param foundLocations Vector of Point where each Point is detected object's top-left point.
@param confidences confidences
@param hitThreshold Threshold for the distance between features and SVM classifying plane. Usually
it is 0 and should be specified in the detector coefficients (as the last free coefficient). But if
the free coefficient is omitted (which is allowed), you can specify it manually here
@param winStride winStride
@param padding padding
*/
virtual void detectROI(InputArray img, const std::vector<cv::Point> &locations,
CV_OUT std::vector<cv::Point>& foundLocations, CV_OUT std::vector<double>& confidences,
double hitThreshold = 0, cv::Size winStride = Size(),
cv::Size padding = Size()) const;
/** @brief evaluate specified ROI and return confidence value for each location in multiple scales
@param img Matrix of the type CV_8U or CV_8UC3 containing an image where objects are detected.
@param foundLocations Vector of rectangles where each rectangle contains the detected object.
@param locations Vector of DetectionROI
@param hitThreshold Threshold for the distance between features and SVM classifying plane. Usually it is 0 and should be specified
in the detector coefficients (as the last free coefficient). But if the free coefficient is omitted (which is allowed), you can specify it manually here.
@param groupThreshold Minimum possible number of rectangles minus 1. The threshold is used in a group of rectangles to retain it.
*/
virtual void detectMultiScaleROI(InputArray img,
CV_OUT std::vector<cv::Rect>& foundLocations,
std::vector<DetectionROI>& locations,
double hitThreshold = 0,
int groupThreshold = 0) const;
/** @brief Groups the object candidate rectangles.
@param rectList Input/output vector of rectangles. Output vector includes retained and grouped rectangles. (The Python list is not modified in place.)
@param weights Input/output vector of weights of rectangles. Output vector includes weights of retained and grouped rectangles. (The Python list is not modified in place.)
@param groupThreshold Minimum possible number of rectangles minus 1. The threshold is used in a group of rectangles to retain it.
@param eps Relative difference between sides of the rectangles to merge them into a group.
*/
void groupRectangles(std::vector<cv::Rect>& rectList, std::vector<double>& weights, int groupThreshold, double eps) const;
};
//! @}
//! @addtogroup objdetect_qrcode
//! @{
@ -854,7 +247,6 @@ public:
//! @}
}
#include "opencv2/objdetect/detection_based_tracker.hpp"
#include "opencv2/objdetect/face.hpp"
#include "opencv2/objdetect/charuco_detector.hpp"
#include "opencv2/objdetect/barcode.hpp"

View File

@ -1,222 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef OPENCV_OBJDETECT_DBT_HPP
#define OPENCV_OBJDETECT_DBT_HPP
#include <opencv2/core.hpp>
#include <vector>
namespace cv
{
//! @addtogroup objdetect_cascade_classifier
//! @{
class CV_EXPORTS DetectionBasedTracker
{
public:
struct CV_EXPORTS Parameters
{
int maxTrackLifetime;
int minDetectionPeriod; //the minimal time between run of the big object detector (on the whole frame) in ms (1000 mean 1 sec), default=0
Parameters();
};
class IDetector
{
public:
IDetector():
minObjSize(96, 96),
maxObjSize(INT_MAX, INT_MAX),
minNeighbours(2),
scaleFactor(1.1f)
{}
virtual void detect(const cv::Mat& image, std::vector<cv::Rect>& objects) = 0;
void setMinObjectSize(const cv::Size& min)
{
minObjSize = min;
}
void setMaxObjectSize(const cv::Size& max)
{
maxObjSize = max;
}
cv::Size getMinObjectSize() const
{
return minObjSize;
}
cv::Size getMaxObjectSize() const
{
return maxObjSize;
}
float getScaleFactor()
{
return scaleFactor;
}
void setScaleFactor(float value)
{
scaleFactor = value;
}
int getMinNeighbours()
{
return minNeighbours;
}
void setMinNeighbours(int value)
{
minNeighbours = value;
}
virtual ~IDetector() {}
protected:
cv::Size minObjSize;
cv::Size maxObjSize;
int minNeighbours;
float scaleFactor;
};
DetectionBasedTracker(cv::Ptr<IDetector> mainDetector, cv::Ptr<IDetector> trackingDetector, const Parameters& params);
virtual ~DetectionBasedTracker();
virtual bool run();
virtual void stop();
virtual void resetTracking();
virtual void process(const cv::Mat& imageGray);
bool setParameters(const Parameters& params);
const Parameters& getParameters() const;
typedef std::pair<cv::Rect, int> Object;
virtual void getObjects(std::vector<cv::Rect>& result) const;
virtual void getObjects(std::vector<Object>& result) const;
enum ObjectStatus
{
DETECTED_NOT_SHOWN_YET,
DETECTED,
DETECTED_TEMPORARY_LOST,
WRONG_OBJECT
};
struct ExtObject
{
int id;
cv::Rect location;
ObjectStatus status;
ExtObject(int _id, cv::Rect _location, ObjectStatus _status)
:id(_id), location(_location), status(_status)
{
}
};
virtual void getObjects(std::vector<ExtObject>& result) const;
virtual int addObject(const cv::Rect& location); //returns id of the new object
protected:
class SeparateDetectionWork;
cv::Ptr<SeparateDetectionWork> separateDetectionWork;
friend void* workcycleObjectDetectorFunction(void* p);
struct InnerParameters
{
int numLastPositionsToTrack;
int numStepsToWaitBeforeFirstShow;
int numStepsToTrackWithoutDetectingIfObjectHasNotBeenShown;
int numStepsToShowWithoutDetecting;
float coeffTrackingWindowSize;
float coeffObjectSizeToTrack;
float coeffObjectSpeedUsingInPrediction;
InnerParameters();
};
Parameters parameters;
InnerParameters innerParameters;
struct TrackedObject
{
typedef std::vector<cv::Rect> PositionsVector;
PositionsVector lastPositions;
int numDetectedFrames;
int numFramesNotDetected;
int id;
TrackedObject(const cv::Rect& rect):numDetectedFrames(1), numFramesNotDetected(0)
{
lastPositions.push_back(rect);
id=getNextId();
}
static int getNextId()
{
static int _id=0;
return _id++;
}
};
int numTrackedSteps;
std::vector<TrackedObject> trackedObjects;
std::vector<float> weightsPositionsSmoothing;
std::vector<float> weightsSizesSmoothing;
cv::Ptr<IDetector> cascadeForTracking;
void updateTrackedObjects(const std::vector<cv::Rect>& detectedObjects);
cv::Rect calcTrackedObjectPositionToShow(int i) const;
cv::Rect calcTrackedObjectPositionToShow(int i, ObjectStatus& status) const;
void detectInRegion(const cv::Mat& img, const cv::Rect& r, std::vector<cv::Rect>& detectedObjectsInRegions);
};
//! @}
} //end of cv namespace
#endif

View File

@ -1,104 +0,0 @@
package org.opencv.test.objdetect;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.objdetect.Objdetect;
import org.opencv.test.OpenCVTestCase;
import org.opencv.test.OpenCVTestRunner;
public class CascadeClassifierTest extends OpenCVTestCase {
private CascadeClassifier cc;
@Override
protected void setUp() throws Exception {
super.setUp();
cc = null;
}
public void testCascadeClassifier() {
cc = new CascadeClassifier();
assertNotNull(cc);
}
public void testCascadeClassifierString() {
cc = new CascadeClassifier(OpenCVTestRunner.LBPCASCADE_FRONTALFACE_PATH);
assertNotNull(cc);
}
public void testDetectMultiScaleMatListOfRect() {
CascadeClassifier cc = new CascadeClassifier(OpenCVTestRunner.LBPCASCADE_FRONTALFACE_PATH);
MatOfRect faces = new MatOfRect();
Mat greyLena = new Mat();
Imgproc.cvtColor(rgbLena, greyLena, Imgproc.COLOR_RGB2GRAY);
Imgproc.equalizeHist(greyLena, greyLena);
cc.detectMultiScale(greyLena, faces, 1.1, 3, Objdetect.CASCADE_SCALE_IMAGE, new Size(30, 30), new Size());
assertEquals(1, faces.total());
}
public void testDetectMultiScaleMatListOfRectDouble() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectDoubleInt() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectDoubleIntInt() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectDoubleIntIntSize() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectDoubleIntIntSizeSize() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfIntegerListOfDouble() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfIntegerListOfDoubleDouble() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfIntegerListOfDoubleDoubleInt() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfIntegerListOfDoubleDoubleIntInt() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfIntegerListOfDoubleDoubleIntIntSize() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfIntegerListOfDoubleDoubleIntIntSizeSize() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfIntegerListOfDoubleDoubleIntIntSizeSizeBoolean() {
fail("Not yet implemented");
}
public void testEmpty() {
cc = new CascadeClassifier();
assertTrue(cc.empty());
}
public void testLoad() {
cc = new CascadeClassifier();
cc.load(OpenCVTestRunner.LBPCASCADE_FRONTALFACE_PATH);
assertFalse(cc.empty());
}
}

View File

@ -1,259 +0,0 @@
package org.opencv.test.objdetect;
import org.opencv.objdetect.HOGDescriptor;
import org.opencv.test.OpenCVTestCase;
public class HOGDescriptorTest extends OpenCVTestCase {
public void testCheckDetectorSize() {
fail("Not yet implemented");
}
public void testComputeGradientMatMatMat() {
fail("Not yet implemented");
}
public void testComputeGradientMatMatMatSize() {
fail("Not yet implemented");
}
public void testComputeGradientMatMatMatSizeSize() {
fail("Not yet implemented");
}
public void testComputeMatListOfFloat() {
fail("Not yet implemented");
}
public void testComputeMatListOfFloatSize() {
fail("Not yet implemented");
}
public void testComputeMatListOfFloatSizeSize() {
fail("Not yet implemented");
}
public void testComputeMatListOfFloatSizeSizeListOfPoint() {
fail("Not yet implemented");
}
public void testDetectMatListOfPoint() {
fail("Not yet implemented");
}
public void testDetectMatListOfPointDouble() {
fail("Not yet implemented");
}
public void testDetectMatListOfPointDoubleSize() {
fail("Not yet implemented");
}
public void testDetectMatListOfPointDoubleSizeSize() {
fail("Not yet implemented");
}
public void testDetectMatListOfPointDoubleSizeSizeListOfPoint() {
fail("Not yet implemented");
}
public void testDetectMatListOfPointListOfDouble() {
fail("Not yet implemented");
}
public void testDetectMatListOfPointListOfDoubleDouble() {
fail("Not yet implemented");
}
public void testDetectMatListOfPointListOfDoubleDoubleSize() {
fail("Not yet implemented");
}
public void testDetectMatListOfPointListOfDoubleDoubleSizeSize() {
fail("Not yet implemented");
}
public void testDetectMatListOfPointListOfDoubleDoubleSizeSizeListOfPoint() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRect() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectDouble() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectDoubleSize() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectDoubleSizeSize() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectDoubleSizeSizeDouble() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectDoubleSizeSizeDoubleDouble() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectDoubleSizeSizeDoubleDoubleBoolean() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfDouble() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfDoubleDouble() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfDoubleDoubleSize() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfDoubleDoubleSizeSize() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfDoubleDoubleSizeSizeDouble() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfDoubleDoubleSizeSizeDoubleDouble() {
fail("Not yet implemented");
}
public void testDetectMultiScaleMatListOfRectListOfDoubleDoubleSizeSizeDoubleDoubleBoolean() {
fail("Not yet implemented");
}
public void testGet_blockSize() {
fail("Not yet implemented");
}
public void testGet_blockStride() {
fail("Not yet implemented");
}
public void testGet_cellSize() {
fail("Not yet implemented");
}
public void testGet_derivAperture() {
fail("Not yet implemented");
}
public void testGet_gammaCorrection() {
fail("Not yet implemented");
}
public void testGet_histogramNormType() {
fail("Not yet implemented");
}
public void testGet_L2HysThreshold() {
fail("Not yet implemented");
}
public void testGet_nbins() {
fail("Not yet implemented");
}
public void testGet_nlevels() {
fail("Not yet implemented");
}
public void testGet_svmDetector() {
fail("Not yet implemented");
}
public void testGet_winSigma() {
fail("Not yet implemented");
}
public void testGet_winSize() {
fail("Not yet implemented");
}
public void testGetDaimlerPeopleDetector() {
fail("Not yet implemented");
}
public void testGetDefaultPeopleDetector() {
fail("Not yet implemented");
}
public void testGetDescriptorSize() {
fail("Not yet implemented");
}
public void testGetWinSigma() {
fail("Not yet implemented");
}
public void testHOGDescriptor() {
HOGDescriptor hog = new HOGDescriptor();
assertNotNull(hog);
assertEquals(HOGDescriptor.DEFAULT_NLEVELS, hog.get_nlevels());
}
public void testHOGDescriptorSizeSizeSizeSizeInt() {
fail("Not yet implemented");
}
public void testHOGDescriptorSizeSizeSizeSizeIntInt() {
fail("Not yet implemented");
}
public void testHOGDescriptorSizeSizeSizeSizeIntIntDouble() {
fail("Not yet implemented");
}
public void testHOGDescriptorSizeSizeSizeSizeIntIntDoubleInt() {
fail("Not yet implemented");
}
public void testHOGDescriptorSizeSizeSizeSizeIntIntDoubleIntDouble() {
fail("Not yet implemented");
}
public void testHOGDescriptorSizeSizeSizeSizeIntIntDoubleIntDoubleBoolean() {
fail("Not yet implemented");
}
public void testHOGDescriptorSizeSizeSizeSizeIntIntDoubleIntDoubleBooleanInt() {
fail("Not yet implemented");
}
public void testHOGDescriptorString() {
fail("Not yet implemented");
}
public void testLoadString() {
fail("Not yet implemented");
}
public void testLoadStringString() {
fail("Not yet implemented");
}
public void testSaveString() {
fail("Not yet implemented");
}
public void testSaveStringString() {
fail("Not yet implemented");
}
public void testSetSVMDetector() {
fail("Not yet implemented");
}
}

View File

@ -1,42 +0,0 @@
package org.opencv.test.objdetect;
import org.opencv.test.OpenCVTestCase;
public class ObjdetectTest extends OpenCVTestCase {
public void testGroupRectanglesListOfRectListOfIntegerInt() {
fail("Not yet implemented");
/*
final int NUM = 10;
MatOfRect rects = new MatOfRect();
rects.alloc(NUM);
for (int i = 0; i < NUM; i++)
rects.put(i, 0, 10, 10, 20, 20);
int groupThreshold = 1;
Objdetect.groupRectangles(rects, null, groupThreshold);//TODO: second parameter should not be null
assertEquals(1, rects.total());
*/
}
public void testGroupRectanglesListOfRectListOfIntegerIntDouble() {
fail("Not yet implemented");
/*
final int NUM = 10;
MatOfRect rects = new MatOfRect();
rects.alloc(NUM);
for (int i = 0; i < NUM; i++)
rects.put(i, 0, 10, 10, 20, 20);
for (int i = 0; i < NUM; i++)
rects.put(i, 0, 10, 10, 25, 25);
int groupThreshold = 1;
double eps = 0.2;
Objdetect.groupRectangles(rects, null, groupThreshold, eps);//TODO: second parameter should not be null
assertEquals(2, rects.size());
*/
}
}

View File

@ -4,7 +4,4 @@
typedef QRCodeEncoder::Params QRCodeEncoder_Params;
typedef HOGDescriptor::HistogramNormType HOGDescriptor_HistogramNormType;
typedef HOGDescriptor::DescriptorStorageFormat HOGDescriptor_DescriptorStorageFormat;
#endif

View File

@ -1,92 +0,0 @@
#!/usr/bin/env python
'''
face detection using haar cascades
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
def detect(img, cascade):
rects = cascade.detectMultiScale(img, scaleFactor=1.275, minNeighbors=4, minSize=(30, 30),
flags=cv.CASCADE_SCALE_IMAGE)
if len(rects) == 0:
return []
rects[:,2:] += rects[:,:2]
return rects
from tests_common import NewOpenCVTests, intersectionRate
class facedetect_test(NewOpenCVTests):
def test_facedetect(self):
cascade_fn = self.repoPath + '/data/haarcascades/haarcascade_frontalface_alt.xml'
nested_fn = self.repoPath + '/data/haarcascades/haarcascade_eye.xml'
cascade = cv.CascadeClassifier(cascade_fn)
nested = cv.CascadeClassifier(nested_fn)
samples = ['samples/data/lena.jpg', 'cv/cascadeandhog/images/mona-lisa.png']
faces = []
eyes = []
testFaces = [
#lena
[[218, 200, 389, 371],
[ 244, 240, 294, 290],
[ 309, 246, 352, 289]],
#lisa
[[167, 119, 307, 259],
[188, 153, 229, 194],
[236, 153, 277, 194]]
]
for sample in samples:
img = self.get_sample( sample)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
gray = cv.GaussianBlur(gray, (5, 5), 0)
rects = detect(gray, cascade)
faces.append(rects)
if not nested.empty():
for x1, y1, x2, y2 in rects:
roi = gray[y1:y2, x1:x2]
subrects = detect(roi.copy(), nested)
for rect in subrects:
rect[0] += x1
rect[2] += x1
rect[1] += y1
rect[3] += y1
eyes.append(subrects)
faces_matches = 0
eyes_matches = 0
eps = 0.8
for i in range(len(faces)):
for j in range(len(testFaces)):
if intersectionRate(faces[i][0], testFaces[j][0]) > eps:
faces_matches += 1
#check eyes
if len(eyes[i]) == 2:
if intersectionRate(eyes[i][0], testFaces[j][1]) > eps and intersectionRate(eyes[i][1] , testFaces[j][2]) > eps:
eyes_matches += 1
elif intersectionRate(eyes[i][1], testFaces[j][1]) > eps and intersectionRate(eyes[i][0], testFaces[j][2]) > eps:
eyes_matches += 1
self.assertEqual(faces_matches, 2)
self.assertEqual(eyes_matches, 2)
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@ -1,65 +0,0 @@
#!/usr/bin/env python
'''
example to detect upright people in images using HOG features
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
def inside(r, q):
rx, ry, rw, rh = r
qx, qy, qw, qh = q
return rx > qx and ry > qy and rx + rw < qx + qw and ry + rh < qy + qh
from tests_common import NewOpenCVTests, intersectionRate
class peopledetect_test(NewOpenCVTests):
def test_peopledetect(self):
hog = cv.HOGDescriptor( (48, 96) )
hog.setSVMDetector( cv.HOGDescriptor_getDaimlerPeopleDetector() )
dirPath = 'samples/data/'
samples = ['basketball1.png', 'basketball2.png']
testPeople = [
[[23, 76, 164, 477], [440, 22, 637, 478]],
[[23, 76, 164, 477], [440, 22, 637, 478]]
]
eps = 0.5
for sample in samples:
img = self.get_sample(dirPath + sample, 0)
found, _w = hog.detectMultiScale(img, winStride=(8,8), padding=(32,32), scale=1.05)
found_filtered = []
for ri, r in enumerate(found):
for qi, q in enumerate(found):
if ri != qi and inside(r, q):
break
else:
found_filtered.append(r)
matches = 0
for i in range(len(found_filtered)):
for j in range(len(testPeople)):
found_rect = (found_filtered[i][0], found_filtered[i][1],
found_filtered[i][0] + found_filtered[i][2],
found_filtered[i][1] + found_filtered[i][3])
if intersectionRate(found_rect, testPeople[j][0]) > eps or intersectionRate(found_rect, testPeople[j][1]) > eps:
matches += 1
self.assertGreater(matches, 0)
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@ -1,61 +0,0 @@
#include "../perf_precomp.hpp"
#include <opencv2/imgproc.hpp>
#include "opencv2/ts/ocl_perf.hpp"
namespace opencv_test
{
using namespace perf;
typedef tuple<std::string, std::string, int> Cascade_Image_MinSize_t;
typedef perf::TestBaseWithParam<Cascade_Image_MinSize_t> Cascade_Image_MinSize;
#ifdef HAVE_OPENCL
OCL_PERF_TEST_P(Cascade_Image_MinSize, CascadeClassifier,
testing::Combine(
testing::Values( string("cv/cascadeandhog/cascades/haarcascade_frontalface_alt.xml"),
string("cv/cascadeandhog/cascades/haarcascade_frontalface_alt2.xml"),
string("cv/cascadeandhog/cascades/lbpcascade_frontalface.xml") ),
testing::Values( string("cv/shared/lena.png"),
string("cv/cascadeandhog/images/bttf301.png"),
string("cv/cascadeandhog/images/class57.png") ),
testing::Values(30, 64, 90) ) )
{
const string cascadePath = get<0>(GetParam());
const string imagePath = get<1>(GetParam());
int min_size = get<2>(GetParam());
Size minSize(min_size, min_size);
CascadeClassifier cc( getDataPath(cascadePath) );
if (cc.empty())
FAIL() << "Can't load cascade file: " << getDataPath(cascadePath);
Mat img = imread(getDataPath(imagePath), IMREAD_GRAYSCALE);
if (img.empty())
FAIL() << "Can't load source image: " << getDataPath(imagePath);
vector<Rect> faces;
equalizeHist(img, img);
declare.in(img).time(60);
UMat uimg = img.getUMat(ACCESS_READ);
while(next())
{
faces.clear();
cvtest::ocl::perf::safeFinish();
startTimer();
cc.detectMultiScale(uimg, faces, 1.1, 3, 0, minSize);
stopTimer();
}
sort(faces.begin(), faces.end(), comparators::RectLess());
SANITY_CHECK(faces, min_size/5);
}
#endif //HAVE_OPENCL
} // namespace

View File

@ -1,93 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Fangfang Bai, fangfang@multicorewareinc.com
// Jin Ma, jin@multicorewareinc.com
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "../perf_precomp.hpp"
#include "opencv2/ts/ocl_perf.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
///////////// HOG////////////////////////
struct RectLess
{
bool operator()(const cv::Rect& a,
const cv::Rect& b) const
{
if (a.x != b.x)
return a.x < b.x;
else if (a.y != b.y)
return a.y < b.y;
else if (a.width != b.width)
return a.width < b.width;
else
return a.height < b.height;
}
};
OCL_PERF_TEST(HOGFixture, HOG)
{
UMat src;
imread(getDataPath("gpu/hog/road.png"), cv::IMREAD_GRAYSCALE).copyTo(src);
ASSERT_FALSE(src.empty());
vector<cv::Rect> found_locations;
declare.in(src);
HOGDescriptor hog;
hog.setSVMDetector(hog.getDefaultPeopleDetector());
OCL_TEST_CYCLE() hog.detectMultiScale(src, found_locations);
std::sort(found_locations.begin(), found_locations.end(), RectLess());
SANITY_CHECK(found_locations, 3);
}
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,656 +0,0 @@
#pragma once
#include "opencv2/core/ocl.hpp"
namespace cv
{
void clipObjects(Size sz, std::vector<Rect>& objects,
std::vector<int>* a, std::vector<double>* b);
class FeatureEvaluator
{
public:
enum
{
HAAR = 0,
LBP = 1,
HOG = 2
};
struct ScaleData
{
ScaleData() { scale = 0.f; layer_ofs = ystep = 0; }
Size getWorkingSize(Size winSize) const
{
return Size(std::max(szi.width - winSize.width, 0),
std::max(szi.height - winSize.height, 0));
}
float scale;
Size szi;
int layer_ofs, ystep;
};
virtual ~FeatureEvaluator();
virtual bool read(const FileNode& node, Size origWinSize);
virtual Ptr<FeatureEvaluator> clone() const;
virtual int getFeatureType() const;
int getNumChannels() const { return nchannels; }
virtual bool setImage(InputArray img, const std::vector<float>& scales);
virtual bool setWindow(Point p, int scaleIdx);
const ScaleData& getScaleData(int scaleIdx) const
{
CV_Assert( 0 <= scaleIdx && scaleIdx < (int)scaleData->size());
return scaleData->at(scaleIdx);
}
virtual void getUMats(std::vector<UMat>& bufs);
virtual void getMats();
Size getLocalSize() const { return localSize; }
Size getLocalBufSize() const { return lbufSize; }
virtual float calcOrd(int featureIdx) const;
virtual int calcCat(int featureIdx) const;
static Ptr<FeatureEvaluator> create(int type);
protected:
enum { SBUF_VALID=1, USBUF_VALID=2 };
int sbufFlag;
bool updateScaleData( Size imgsz, const std::vector<float>& _scales );
virtual void computeChannels( int, InputArray ) {}
virtual void computeOptFeatures() {}
Size origWinSize, sbufSize, localSize, lbufSize;
int nchannels;
Mat sbuf, rbuf;
UMat urbuf, usbuf, ufbuf, uscaleData;
Ptr<std::vector<ScaleData> > scaleData;
};
class CascadeClassifierImpl CV_FINAL : public BaseCascadeClassifier
{
public:
CascadeClassifierImpl();
virtual ~CascadeClassifierImpl() CV_OVERRIDE;
bool empty() const CV_OVERRIDE;
bool load( const String& filename ) CV_OVERRIDE;
void read( const FileNode& node ) CV_OVERRIDE;
bool read_( const FileNode& node );
void detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& objects,
double scaleFactor = 1.1,
int minNeighbors = 3, int flags = 0,
Size minSize = Size(),
Size maxSize = Size() ) CV_OVERRIDE;
void detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& objects,
CV_OUT std::vector<int>& numDetections,
double scaleFactor=1.1,
int minNeighbors=3, int flags=0,
Size minSize=Size(),
Size maxSize=Size() ) CV_OVERRIDE;
void detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& objects,
CV_OUT std::vector<int>& rejectLevels,
CV_OUT std::vector<double>& levelWeights,
double scaleFactor = 1.1,
int minNeighbors = 3, int flags = 0,
Size minSize = Size(),
Size maxSize = Size(),
bool outputRejectLevels = false ) CV_OVERRIDE;
bool isOldFormatCascade() const CV_OVERRIDE;
Size getOriginalWindowSize() const CV_OVERRIDE;
int getFeatureType() const CV_OVERRIDE;
void* getOldCascade() CV_OVERRIDE;
void setMaskGenerator(const Ptr<MaskGenerator>& maskGenerator) CV_OVERRIDE;
Ptr<MaskGenerator> getMaskGenerator() CV_OVERRIDE;
protected:
enum { SUM_ALIGN = 64 };
bool detectSingleScale( InputArray image, Size processingRectSize,
int yStep, double factor, std::vector<Rect>& candidates,
std::vector<int>& rejectLevels, std::vector<double>& levelWeights,
Size sumSize0, bool outputRejectLevels = false );
#ifdef HAVE_OPENCL
bool ocl_detectMultiScaleNoGrouping( const std::vector<float>& scales,
std::vector<Rect>& candidates );
#endif
void detectMultiScaleNoGrouping( InputArray image, std::vector<Rect>& candidates,
std::vector<int>& rejectLevels, std::vector<double>& levelWeights,
double scaleFactor, Size minObjectSize, Size maxObjectSize,
bool outputRejectLevels = false );
enum { MAX_FACES = 10000 };
enum { BOOST = 0 };
enum { DO_CANNY_PRUNING = CASCADE_DO_CANNY_PRUNING,
SCALE_IMAGE = CASCADE_SCALE_IMAGE,
FIND_BIGGEST_OBJECT = CASCADE_FIND_BIGGEST_OBJECT,
DO_ROUGH_SEARCH = CASCADE_DO_ROUGH_SEARCH
};
friend class CascadeClassifierInvoker;
friend class SparseCascadeClassifierInvoker;
template<class FEval>
friend int predictOrdered( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);
template<class FEval>
friend int predictCategorical( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);
template<class FEval>
friend int predictOrderedStump( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);
template<class FEval>
friend int predictCategoricalStump( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);
int runAt( Ptr<FeatureEvaluator>& feval, Point pt, int scaleIdx, double& weight );
class Data
{
public:
struct DTreeNode
{
int featureIdx;
float threshold; // for ordered features only
int left;
int right;
};
struct DTree
{
int nodeCount;
};
struct Stage
{
int first;
int ntrees;
float threshold;
};
struct Stump
{
Stump() : featureIdx(0), threshold(0), left(0), right(0) { }
Stump(int _featureIdx, float _threshold, float _left, float _right)
: featureIdx(_featureIdx), threshold(_threshold), left(_left), right(_right) {}
int featureIdx;
float threshold;
float left;
float right;
};
Data();
bool read(const FileNode &node);
int stageType;
int featureType;
int ncategories;
int minNodesPerTree, maxNodesPerTree;
Size origWinSize;
std::vector<Stage> stages;
std::vector<DTree> classifiers;
std::vector<DTreeNode> nodes;
std::vector<float> leaves;
std::vector<int> subsets;
std::vector<Stump> stumps;
};
Data data;
Ptr<FeatureEvaluator> featureEvaluator;
Ptr<CvHaarClassifierCascade> oldCascade;
Ptr<MaskGenerator> maskGenerator;
UMat ugrayImage;
UMat ufacepos, ustages, unodes, uleaves, usubsets;
#ifdef HAVE_OPENCL
ocl::Kernel haarKernel, lbpKernel;
bool tryOpenCL;
#endif
Mutex mtx;
};
#define CC_CASCADE_PARAMS "cascadeParams"
#define CC_STAGE_TYPE "stageType"
#define CC_FEATURE_TYPE "featureType"
#define CC_HEIGHT "height"
#define CC_WIDTH "width"
#define CC_STAGE_NUM "stageNum"
#define CC_STAGES "stages"
#define CC_STAGE_PARAMS "stageParams"
#define CC_BOOST "BOOST"
#define CC_MAX_DEPTH "maxDepth"
#define CC_WEAK_COUNT "maxWeakCount"
#define CC_STAGE_THRESHOLD "stageThreshold"
#define CC_WEAK_CLASSIFIERS "weakClassifiers"
#define CC_INTERNAL_NODES "internalNodes"
#define CC_LEAF_VALUES "leafValues"
#define CC_FEATURES "features"
#define CC_FEATURE_PARAMS "featureParams"
#define CC_MAX_CAT_COUNT "maxCatCount"
#define CC_HAAR "HAAR"
#define CC_RECTS "rects"
#define CC_TILTED "tilted"
#define CC_LBP "LBP"
#define CC_RECT "rect"
#define CC_HOG "HOG"
#define CV_SUM_PTRS( p0, p1, p2, p3, sum, rect, step ) \
/* (x, y) */ \
(p0) = sum + (rect).x + (step) * (rect).y, \
/* (x + w, y) */ \
(p1) = sum + (rect).x + (rect).width + (step) * (rect).y, \
/* (x, y + h) */ \
(p2) = sum + (rect).x + (step) * ((rect).y + (rect).height), \
/* (x + w, y + h) */ \
(p3) = sum + (rect).x + (rect).width + (step) * ((rect).y + (rect).height)
#define CV_TILTED_PTRS( p0, p1, p2, p3, tilted, rect, step ) \
/* (x, y) */ \
(p0) = tilted + (rect).x + (step) * (rect).y, \
/* (x - h, y + h) */ \
(p1) = tilted + (rect).x - (rect).height + (step) * ((rect).y + (rect).height), \
/* (x + w, y + w) */ \
(p2) = tilted + (rect).x + (rect).width + (step) * ((rect).y + (rect).width), \
/* (x + w - h, y + w + h) */ \
(p3) = tilted + (rect).x + (rect).width - (rect).height \
+ (step) * ((rect).y + (rect).width + (rect).height)
#define CALC_SUM_(p0, p1, p2, p3, offset) \
((p0)[offset] - (p1)[offset] - (p2)[offset] + (p3)[offset])
#define CALC_SUM(rect,offset) CALC_SUM_((rect)[0], (rect)[1], (rect)[2], (rect)[3], offset)
#define CV_SUM_OFS( p0, p1, p2, p3, sum, rect, step ) \
/* (x, y) */ \
(p0) = sum + (rect).x + (step) * (rect).y, \
/* (x + w, y) */ \
(p1) = sum + (rect).x + (rect).width + (step) * (rect).y, \
/* (x, y + h) */ \
(p2) = sum + (rect).x + (step) * ((rect).y + (rect).height), \
/* (x + w, y + h) */ \
(p3) = sum + (rect).x + (rect).width + (step) * ((rect).y + (rect).height)
#define CV_TILTED_OFS( p0, p1, p2, p3, tilted, rect, step ) \
/* (x, y) */ \
(p0) = tilted + (rect).x + (step) * (rect).y, \
/* (x - h, y + h) */ \
(p1) = tilted + (rect).x - (rect).height + (step) * ((rect).y + (rect).height), \
/* (x + w, y + w) */ \
(p2) = tilted + (rect).x + (rect).width + (step) * ((rect).y + (rect).width), \
/* (x + w - h, y + w + h) */ \
(p3) = tilted + (rect).x + (rect).width - (rect).height \
+ (step) * ((rect).y + (rect).width + (rect).height)
#define CALC_SUM_OFS_(p0, p1, p2, p3, ptr) \
((ptr)[p0] - (ptr)[p1] - (ptr)[p2] + (ptr)[p3])
#define CALC_SUM_OFS(rect, ptr) CALC_SUM_OFS_((rect)[0], (rect)[1], (rect)[2], (rect)[3], ptr)
//---------------------------------------------- HaarEvaluator ---------------------------------------
class HaarEvaluator CV_FINAL : public FeatureEvaluator
{
public:
struct Feature
{
Feature();
bool read(const FileNode& node, const Size& origWinSize);
bool tilted;
enum { RECT_NUM = 3 };
struct RectWeigth
{
Rect r;
float weight;
} rect[RECT_NUM];
};
struct OptFeature
{
OptFeature();
enum { RECT_NUM = Feature::RECT_NUM };
float calc( const int* pwin ) const;
void setOffsets( const Feature& _f, int step, int tofs );
int ofs[RECT_NUM][4];
float weight[4];
};
HaarEvaluator();
virtual ~HaarEvaluator() CV_OVERRIDE;
virtual bool read( const FileNode& node, Size origWinSize) CV_OVERRIDE;
virtual Ptr<FeatureEvaluator> clone() const CV_OVERRIDE;
virtual int getFeatureType() const CV_OVERRIDE { return FeatureEvaluator::HAAR; }
virtual bool setWindow(Point p, int scaleIdx) CV_OVERRIDE;
Rect getNormRect() const;
int getSquaresOffset() const;
float operator()(int featureIdx) const
{ return optfeaturesPtr[featureIdx].calc(pwin) * varianceNormFactor; }
virtual float calcOrd(int featureIdx) const CV_OVERRIDE
{ return (*this)(featureIdx); }
protected:
virtual void computeChannels( int i, InputArray img ) CV_OVERRIDE;
virtual void computeOptFeatures() CV_OVERRIDE;
Ptr<std::vector<Feature> > features;
Ptr<std::vector<OptFeature> > optfeatures;
Ptr<std::vector<OptFeature> > optfeatures_lbuf;
bool hasTiltedFeatures;
int tofs, sqofs;
Vec4i nofs;
Rect normrect;
const int* pwin;
OptFeature* optfeaturesPtr; // optimization
float varianceNormFactor;
};
inline HaarEvaluator::Feature :: Feature()
{
tilted = false;
rect[0].r = rect[1].r = rect[2].r = Rect();
rect[0].weight = rect[1].weight = rect[2].weight = 0;
}
inline HaarEvaluator::OptFeature :: OptFeature()
{
weight[0] = weight[1] = weight[2] = 0.f;
ofs[0][0] = ofs[0][1] = ofs[0][2] = ofs[0][3] =
ofs[1][0] = ofs[1][1] = ofs[1][2] = ofs[1][3] =
ofs[2][0] = ofs[2][1] = ofs[2][2] = ofs[2][3] = 0;
}
inline float HaarEvaluator::OptFeature :: calc( const int* ptr ) const
{
float ret = weight[0] * CALC_SUM_OFS(ofs[0], ptr) +
weight[1] * CALC_SUM_OFS(ofs[1], ptr);
if( weight[2] != 0.0f )
ret += weight[2] * CALC_SUM_OFS(ofs[2], ptr);
return ret;
}
//---------------------------------------------- LBPEvaluator -------------------------------------
class LBPEvaluator CV_FINAL : public FeatureEvaluator
{
public:
struct Feature
{
Feature();
Feature( int x, int y, int _block_w, int _block_h ) :
rect(x, y, _block_w, _block_h) {}
bool read(const FileNode& node, const Size& origWinSize);
Rect rect; // weight and height for block
};
struct OptFeature
{
OptFeature();
int calc( const int* pwin ) const;
void setOffsets( const Feature& _f, int step );
int ofs[16];
};
LBPEvaluator();
virtual ~LBPEvaluator() CV_OVERRIDE;
virtual bool read( const FileNode& node, Size origWinSize ) CV_OVERRIDE;
virtual Ptr<FeatureEvaluator> clone() const CV_OVERRIDE;
virtual int getFeatureType() const CV_OVERRIDE { return FeatureEvaluator::LBP; }
virtual bool setWindow(Point p, int scaleIdx) CV_OVERRIDE;
int operator()(int featureIdx) const
{ return optfeaturesPtr[featureIdx].calc(pwin); }
virtual int calcCat(int featureIdx) const CV_OVERRIDE
{ return (*this)(featureIdx); }
protected:
virtual void computeChannels( int i, InputArray img ) CV_OVERRIDE;
virtual void computeOptFeatures() CV_OVERRIDE;
Ptr<std::vector<Feature> > features;
Ptr<std::vector<OptFeature> > optfeatures;
Ptr<std::vector<OptFeature> > optfeatures_lbuf;
OptFeature* optfeaturesPtr; // optimization
const int* pwin;
};
inline LBPEvaluator::Feature :: Feature()
{
rect = Rect();
}
inline LBPEvaluator::OptFeature :: OptFeature()
{
for( int i = 0; i < 16; i++ )
ofs[i] = 0;
}
inline int LBPEvaluator::OptFeature :: calc( const int* p ) const
{
int cval = CALC_SUM_OFS_( ofs[5], ofs[6], ofs[9], ofs[10], p );
return (CALC_SUM_OFS_( ofs[0], ofs[1], ofs[4], ofs[5], p ) >= cval ? 128 : 0) | // 0
(CALC_SUM_OFS_( ofs[1], ofs[2], ofs[5], ofs[6], p ) >= cval ? 64 : 0) | // 1
(CALC_SUM_OFS_( ofs[2], ofs[3], ofs[6], ofs[7], p ) >= cval ? 32 : 0) | // 2
(CALC_SUM_OFS_( ofs[6], ofs[7], ofs[10], ofs[11], p ) >= cval ? 16 : 0) | // 5
(CALC_SUM_OFS_( ofs[10], ofs[11], ofs[14], ofs[15], p ) >= cval ? 8 : 0)| // 8
(CALC_SUM_OFS_( ofs[9], ofs[10], ofs[13], ofs[14], p ) >= cval ? 4 : 0)| // 7
(CALC_SUM_OFS_( ofs[8], ofs[9], ofs[12], ofs[13], p ) >= cval ? 2 : 0)| // 6
(CALC_SUM_OFS_( ofs[4], ofs[5], ofs[8], ofs[9], p ) >= cval ? 1 : 0);
}
//---------------------------------------------- predictor functions -------------------------------------
template<class FEval>
inline int predictOrdered( CascadeClassifierImpl& cascade,
Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
{
CV_INSTRUMENT_REGION();
int nstages = (int)cascade.data.stages.size();
int nodeOfs = 0, leafOfs = 0;
FEval& featureEvaluator = (FEval&)*_featureEvaluator;
float* cascadeLeaves = &cascade.data.leaves[0];
CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
CascadeClassifierImpl::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0];
CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];
for( int si = 0; si < nstages; si++ )
{
CascadeClassifierImpl::Data::Stage& stage = cascadeStages[si];
int wi, ntrees = stage.ntrees;
sum = 0;
for( wi = 0; wi < ntrees; wi++ )
{
CascadeClassifierImpl::Data::DTree& weak = cascadeWeaks[stage.first + wi];
int idx = 0, root = nodeOfs;
do
{
CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[root + idx];
double val = featureEvaluator(node.featureIdx);
idx = val < node.threshold ? node.left : node.right;
}
while( idx > 0 );
sum += cascadeLeaves[leafOfs - idx];
nodeOfs += weak.nodeCount;
leafOfs += weak.nodeCount + 1;
}
if( sum < stage.threshold )
return -si;
}
return 1;
}
template<class FEval>
inline int predictCategorical( CascadeClassifierImpl& cascade,
Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
{
CV_INSTRUMENT_REGION();
int nstages = (int)cascade.data.stages.size();
int nodeOfs = 0, leafOfs = 0;
FEval& featureEvaluator = (FEval&)*_featureEvaluator;
size_t subsetSize = (cascade.data.ncategories + 31)/32;
int* cascadeSubsets = &cascade.data.subsets[0];
float* cascadeLeaves = &cascade.data.leaves[0];
CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
CascadeClassifierImpl::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0];
CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];
for(int si = 0; si < nstages; si++ )
{
CascadeClassifierImpl::Data::Stage& stage = cascadeStages[si];
int wi, ntrees = stage.ntrees;
sum = 0;
for( wi = 0; wi < ntrees; wi++ )
{
CascadeClassifierImpl::Data::DTree& weak = cascadeWeaks[stage.first + wi];
int idx = 0, root = nodeOfs;
do
{
CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[root + idx];
int c = featureEvaluator(node.featureIdx);
const int* subset = &cascadeSubsets[(root + idx)*subsetSize];
idx = (subset[c>>5] & (1 << (c & 31))) ? node.left : node.right;
}
while( idx > 0 );
sum += cascadeLeaves[leafOfs - idx];
nodeOfs += weak.nodeCount;
leafOfs += weak.nodeCount + 1;
}
if( sum < stage.threshold )
return -si;
}
return 1;
}
template<class FEval>
inline int predictOrderedStump( CascadeClassifierImpl& cascade,
Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
{
CV_INSTRUMENT_REGION();
CV_Assert(!cascade.data.stumps.empty());
FEval& featureEvaluator = (FEval&)*_featureEvaluator;
const CascadeClassifierImpl::Data::Stump* cascadeStumps = &cascade.data.stumps[0];
const CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];
int nstages = (int)cascade.data.stages.size();
double tmp = 0;
for( int stageIdx = 0; stageIdx < nstages; stageIdx++ )
{
const CascadeClassifierImpl::Data::Stage& stage = cascadeStages[stageIdx];
tmp = 0;
int ntrees = stage.ntrees;
for( int i = 0; i < ntrees; i++ )
{
const CascadeClassifierImpl::Data::Stump& stump = cascadeStumps[i];
double value = featureEvaluator(stump.featureIdx);
tmp += value < stump.threshold ? stump.left : stump.right;
}
if( tmp < stage.threshold )
{
sum = (double)tmp;
return -stageIdx;
}
cascadeStumps += ntrees;
}
sum = (double)tmp;
return 1;
}
template<class FEval>
inline int predictCategoricalStump( CascadeClassifierImpl& cascade,
Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
{
CV_INSTRUMENT_REGION();
CV_Assert(!cascade.data.stumps.empty());
int nstages = (int)cascade.data.stages.size();
FEval& featureEvaluator = (FEval&)*_featureEvaluator;
size_t subsetSize = (cascade.data.ncategories + 31)/32;
const int* cascadeSubsets = &cascade.data.subsets[0];
const CascadeClassifierImpl::Data::Stump* cascadeStumps = &cascade.data.stumps[0];
const CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];
double tmp = 0;
for( int si = 0; si < nstages; si++ )
{
const CascadeClassifierImpl::Data::Stage& stage = cascadeStages[si];
int wi, ntrees = stage.ntrees;
tmp = 0;
for( wi = 0; wi < ntrees; wi++ )
{
const CascadeClassifierImpl::Data::Stump& stump = cascadeStumps[wi];
int c = featureEvaluator(stump.featureIdx);
const int* subset = &cascadeSubsets[wi*subsetSize];
tmp += (subset[c>>5] & (1 << (c & 31))) ? stump.left : stump.right;
}
if( tmp < stage.threshold )
{
sum = tmp;
return -si;
}
cascadeStumps += ntrees;
cascadeSubsets += ntrees*subsetSize;
}
sum = (double)tmp;
return 1;
}
namespace haar_cvt
{
bool convert(const FileNode& oldcascade_root, FileStorage& newfs);
}
}

View File

@ -1,275 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, Itseez Inc, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
/* Haar features calculation */
#include "precomp.hpp"
#include "cascadedetect.hpp"
#include <stdio.h>
namespace cv
{
/* field names */
#define ICV_HAAR_SIZE_NAME "size"
#define ICV_HAAR_STAGES_NAME "stages"
#define ICV_HAAR_TREES_NAME "trees"
#define ICV_HAAR_FEATURE_NAME "feature"
#define ICV_HAAR_RECTS_NAME "rects"
#define ICV_HAAR_TILTED_NAME "tilted"
#define ICV_HAAR_THRESHOLD_NAME "threshold"
#define ICV_HAAR_LEFT_NODE_NAME "left_node"
#define ICV_HAAR_LEFT_VAL_NAME "left_val"
#define ICV_HAAR_RIGHT_NODE_NAME "right_node"
#define ICV_HAAR_RIGHT_VAL_NAME "right_val"
#define ICV_HAAR_STAGE_THRESHOLD_NAME "stage_threshold"
#define ICV_HAAR_PARENT_NAME "parent"
#define ICV_HAAR_NEXT_NAME "next"
namespace haar_cvt
{
struct HaarFeature
{
enum { RECT_NUM = 3 };
HaarFeature()
{
tilted = false;
for( int i = 0; i < RECT_NUM; i++ )
{
rect[i].r = Rect(0,0,0,0);
rect[i].weight = 0.f;
}
}
bool tilted;
struct
{
Rect r;
float weight;
} rect[RECT_NUM];
};
struct HaarClassifierNode
{
HaarClassifierNode()
{
f = left = right = 0;
threshold = 0.f;
}
int f, left, right;
float threshold;
};
struct HaarClassifier
{
std::vector<HaarClassifierNode> nodes;
std::vector<float> leaves;
};
struct HaarStageClassifier
{
HaarStageClassifier() : threshold(0) {}
double threshold;
std::vector<HaarClassifier> weaks;
};
bool convert(const FileNode& oldroot, FileStorage& newfs)
{
FileNode sznode = oldroot[ICV_HAAR_SIZE_NAME];
if( sznode.empty() )
return false;
Size cascadesize;
cascadesize.width = (int)sznode[0];
cascadesize.height = (int)sznode[1];
std::vector<HaarFeature> features;
int i, j, k, n;
FileNode stages_seq = oldroot[ICV_HAAR_STAGES_NAME];
int nstages = (int)stages_seq.size();
std::vector<HaarStageClassifier> stages(nstages);
for( i = 0; i < nstages; i++ )
{
FileNode stagenode = stages_seq[i];
HaarStageClassifier& stage = stages[i];
stage.threshold = (double)stagenode[ICV_HAAR_STAGE_THRESHOLD_NAME];
FileNode weaks_seq = stagenode[ICV_HAAR_TREES_NAME];
int nweaks = (int)weaks_seq.size();
stage.weaks.resize(nweaks);
for( j = 0; j < nweaks; j++ )
{
HaarClassifier& weak = stage.weaks[j];
FileNode weaknode = weaks_seq[j];
int nnodes = (int)weaknode.size();
for( n = 0; n < nnodes; n++ )
{
FileNode nnode = weaknode[n];
FileNode fnode = nnode[ICV_HAAR_FEATURE_NAME];
HaarFeature f;
HaarClassifierNode node;
node.f = (int)features.size();
f.tilted = (int)fnode[ICV_HAAR_TILTED_NAME] != 0;
FileNode rects_seq = fnode[ICV_HAAR_RECTS_NAME];
int nrects = (int)rects_seq.size();
for( k = 0; k < nrects; k++ )
{
FileNode rnode = rects_seq[k];
f.rect[k].r.x = (int)rnode[0];
f.rect[k].r.y = (int)rnode[1];
f.rect[k].r.width = (int)rnode[2];
f.rect[k].r.height = (int)rnode[3];
f.rect[k].weight = (float)rnode[4];
}
features.push_back(f);
node.threshold = nnode[ICV_HAAR_THRESHOLD_NAME];
FileNode leftValNode = nnode[ICV_HAAR_LEFT_VAL_NAME];
if( !leftValNode.empty() )
{
node.left = -(int)weak.leaves.size();
weak.leaves.push_back((float)leftValNode);
}
else
{
node.left = (int)nnode[ICV_HAAR_LEFT_NODE_NAME];
}
FileNode rightValNode = nnode[ICV_HAAR_RIGHT_VAL_NAME];
if( !rightValNode.empty() )
{
node.right = -(int)weak.leaves.size();
weak.leaves.push_back((float)rightValNode);
}
else
{
node.right = (int)nnode[ICV_HAAR_RIGHT_NODE_NAME];
}
weak.nodes.push_back(node);
}
}
}
int maxWeakCount = 0, nfeatures = (int)features.size();
for( i = 0; i < nstages; i++ )
maxWeakCount = std::max(maxWeakCount, (int)stages[i].weaks.size());
newfs << "cascade" << "{:opencv-cascade-classifier"
<< "stageType" << "BOOST"
<< "featureType" << "HAAR"
<< "width" << cascadesize.width
<< "height" << cascadesize.height
<< "stageParams" << "{"
<< "maxWeakCount" << (int)maxWeakCount
<< "}"
<< "featureParams" << "{"
<< "maxCatCount" << 0
<< "}"
<< "stageNum" << (int)nstages
<< "stages" << "[";
for( i = 0; i < nstages; i++ )
{
int nweaks = (int)stages[i].weaks.size();
newfs << "{" << "maxWeakCount" << (int)nweaks
<< "stageThreshold" << stages[i].threshold
<< "weakClassifiers" << "[";
for( j = 0; j < nweaks; j++ )
{
const HaarClassifier& c = stages[i].weaks[j];
newfs << "{" << "internalNodes" << "[:";
int nnodes = (int)c.nodes.size(), nleaves = (int)c.leaves.size();
for( k = 0; k < nnodes; k++ )
newfs << c.nodes[k].left << c.nodes[k].right
<< c.nodes[k].f << c.nodes[k].threshold;
newfs << "]" << "leafValues" << "[:";
for( k = 0; k < nleaves; k++ )
newfs << c.leaves[k];
newfs << "]" << "}";
}
newfs << "]" << "}";
}
newfs << "]"
<< "features" << "[";
for( i = 0; i < nfeatures; i++ )
{
const HaarFeature& f = features[i];
newfs << "{" << "rects" << "[";
for( j = 0; j < HaarFeature::RECT_NUM; j++ )
{
if( j >= 2 && fabs(f.rect[j].weight) < FLT_EPSILON )
break;
newfs << "[:" << f.rect[j].r.x << f.rect[j].r.y <<
f.rect[j].r.width << f.rect[j].r.height << f.rect[j].weight << "]";
}
newfs << "]";
if( f.tilted )
newfs << "tilted" << 1;
newfs << "}";
}
newfs << "]" << "}";
return true;
}
}
bool CascadeClassifier::convert(const String& oldcascade, const String& newcascade)
{
FileStorage oldfs(oldcascade, FileStorage::READ);
FileStorage newfs(newcascade, FileStorage::WRITE);
if( !oldfs.isOpened() || !newfs.isOpened() )
return false;
FileNode oldroot = oldfs.getFirstTopLevelNode();
bool ok = haar_cvt::convert(oldroot, newfs);
if( !ok && newcascade.size() > 0 )
remove(newcascade.c_str());
return ok;
}
}

View File

@ -1,885 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
#include "opencv2/core/utility.hpp"
#include <thread>
#include <mutex>
#include <condition_variable>
#if defined(DEBUG) || defined(_DEBUG)
#undef DEBUGLOGS
#define DEBUGLOGS 1
#endif
#ifndef DEBUGLOGS
#define DEBUGLOGS 0
#endif
#ifdef __ANDROID__
#include <android/log.h>
#define LOG_TAG "OBJECT_DETECTOR"
#define LOGD0(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#define LOGI0(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOGW0(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
#define LOGE0(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#else
#include <stdio.h>
#define LOGD0(_str, ...) (printf(_str , ## __VA_ARGS__), printf("\n"), fflush(stdout))
#define LOGI0(_str, ...) (printf(_str , ## __VA_ARGS__), printf("\n"), fflush(stdout))
#define LOGW0(_str, ...) (printf(_str , ## __VA_ARGS__), printf("\n"), fflush(stdout))
#define LOGE0(_str, ...) (printf(_str , ## __VA_ARGS__), printf("\n"), fflush(stdout))
#endif //__ANDROID__
#if DEBUGLOGS
#define LOGD(_str, ...) LOGD0(_str , ## __VA_ARGS__)
#define LOGI(_str, ...) LOGI0(_str , ## __VA_ARGS__)
#define LOGW(_str, ...) LOGW0(_str , ## __VA_ARGS__)
#define LOGE(_str, ...) LOGE0(_str , ## __VA_ARGS__)
#else
#define LOGD(...)
#define LOGI(...)
#define LOGW(...)
#define LOGE(...)
#endif //DEBUGLOGS
using namespace cv;
static inline cv::Point2f centerRect(const cv::Rect& r)
{
return cv::Point2f(r.x+((float)r.width)/2, r.y+((float)r.height)/2);
}
static inline cv::Rect scale_rect(const cv::Rect& r, float scale)
{
cv::Point2f m=centerRect(r);
float width = r.width * scale;
float height = r.height * scale;
int x=cvRound(m.x - width/2);
int y=cvRound(m.y - height/2);
return cv::Rect(x, y, cvRound(width), cvRound(height));
}
namespace cv
{
void* workcycleObjectDetectorFunction(void* p);
}
class cv::DetectionBasedTracker::SeparateDetectionWork
{
public:
SeparateDetectionWork(cv::DetectionBasedTracker& _detectionBasedTracker, cv::Ptr<DetectionBasedTracker::IDetector> _detector,
const cv::DetectionBasedTracker::Parameters& params);
virtual ~SeparateDetectionWork();
bool communicateWithDetectingThread(const Mat& imageGray, std::vector<Rect>& rectsWhereRegions);
bool run();
void stop();
void resetTracking();
inline bool isWorking()
{
return (stateThread==STATE_THREAD_WORKING_SLEEPING) || (stateThread==STATE_THREAD_WORKING_WITH_IMAGE);
}
void setParameters(const cv::DetectionBasedTracker::Parameters& params)
{
std::unique_lock<std::mutex> mtx_lock(mtx);
parameters = params;
}
inline void init()
{
std::unique_lock<std::mutex> mtx_lock(mtx);
stateThread = STATE_THREAD_STOPPED;
isObjectDetectingReady = false;
shouldObjectDetectingResultsBeForgot = false;
objectDetectorThreadStartStop.notify_one();
}
protected:
DetectionBasedTracker& detectionBasedTracker;
cv::Ptr<DetectionBasedTracker::IDetector> cascadeInThread;
std::thread second_workthread;
std::mutex mtx;
std::condition_variable objectDetectorRun;
std::condition_variable objectDetectorThreadStartStop;
std::vector<cv::Rect> resultDetect;
volatile bool isObjectDetectingReady;
volatile bool shouldObjectDetectingResultsBeForgot;
enum StateSeparatedThread {
STATE_THREAD_STOPPED=0,
STATE_THREAD_WORKING_SLEEPING,
STATE_THREAD_WORKING_WITH_IMAGE,
STATE_THREAD_WORKING,
STATE_THREAD_STOPPING
};
volatile StateSeparatedThread stateThread;
cv::Mat imageSeparateDetecting;
void workcycleObjectDetector();
friend void* workcycleObjectDetectorFunction(void* p);
long long timeWhenDetectingThreadStartedWork;
cv::DetectionBasedTracker::Parameters parameters;
};
cv::DetectionBasedTracker::SeparateDetectionWork::SeparateDetectionWork(DetectionBasedTracker& _detectionBasedTracker, cv::Ptr<DetectionBasedTracker::IDetector> _detector,
const cv::DetectionBasedTracker::Parameters& params)
:detectionBasedTracker(_detectionBasedTracker),
cascadeInThread(),
isObjectDetectingReady(false),
shouldObjectDetectingResultsBeForgot(false),
stateThread(STATE_THREAD_STOPPED),
timeWhenDetectingThreadStartedWork(-1),
parameters(params)
{
CV_Assert(_detector);
cascadeInThread = _detector;
}
cv::DetectionBasedTracker::SeparateDetectionWork::~SeparateDetectionWork()
{
if(stateThread!=STATE_THREAD_STOPPED) {
LOGE("\n\n\nATTENTION!!! dangerous algorithm error: destructor DetectionBasedTracker::DetectionBasedTracker::~SeparateDetectionWork is called before stopping the workthread");
}
second_workthread.join();
}
bool cv::DetectionBasedTracker::SeparateDetectionWork::run()
{
LOGD("DetectionBasedTracker::SeparateDetectionWork::run() --- start");
std::unique_lock<std::mutex> mtx_lock(mtx);
// unlocked when leaving scope
if (stateThread != STATE_THREAD_STOPPED) {
LOGE("DetectionBasedTracker::SeparateDetectionWork::run is called while the previous run is not stopped");
return false;
}
stateThread=STATE_THREAD_WORKING_SLEEPING;
second_workthread = std::thread(workcycleObjectDetectorFunction, (void*)this); //TODO: add attributes?
objectDetectorThreadStartStop.wait(mtx_lock);
LOGD("DetectionBasedTracker::SeparateDetectionWork::run --- end");
return true;
}
#define CATCH_ALL_AND_LOG(_block) \
try { \
_block; \
} \
catch(const cv::Exception& e) { \
LOGE0("\n %s: ERROR: OpenCV Exception caught: \n'%s'\n\n", CV_Func, e.what()); \
} catch(const std::exception& e) { \
LOGE0("\n %s: ERROR: Exception caught: \n'%s'\n\n", CV_Func, e.what()); \
} catch(...) { \
LOGE0("\n %s: ERROR: UNKNOWN Exception caught\n\n", CV_Func); \
}
void* cv::workcycleObjectDetectorFunction(void* p)
{
CATCH_ALL_AND_LOG({ ((cv::DetectionBasedTracker::SeparateDetectionWork*)p)->workcycleObjectDetector(); });
try{
((cv::DetectionBasedTracker::SeparateDetectionWork*)p)->init();
} catch(...) {
LOGE0("DetectionBasedTracker: workcycleObjectDetectorFunction: ERROR concerning pointer, received as the function parameter");
}
return NULL;
}
void cv::DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector()
{
static double freq = getTickFrequency();
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- start");
std::vector<Rect> objects;
CV_Assert(stateThread==STATE_THREAD_WORKING_SLEEPING);
std::unique_lock<std::mutex> mtx_lock(mtx);
{
objectDetectorThreadStartStop.notify_one();
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- before waiting");
CV_Assert(stateThread==STATE_THREAD_WORKING_SLEEPING);
objectDetectorRun.wait(mtx_lock);
if (isWorking()) {
stateThread=STATE_THREAD_WORKING_WITH_IMAGE;
}
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- after waiting");
}
mtx_lock.unlock();
bool isFirstStep=true;
isObjectDetectingReady=false;
while(isWorking())
{
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- next step");
if (! isFirstStep) {
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- before waiting");
CV_Assert(stateThread==STATE_THREAD_WORKING_SLEEPING);
mtx_lock.lock();
if (!isWorking()) {//it is a rare case, but may cause a crash
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- go out from the workcycle from inner part of lock just before waiting");
mtx_lock.unlock();
break;
}
CV_Assert(stateThread==STATE_THREAD_WORKING_SLEEPING);
objectDetectorRun.wait(mtx_lock);
if (isWorking()) {
stateThread=STATE_THREAD_WORKING_WITH_IMAGE;
}
mtx_lock.unlock();
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- after waiting");
} else {
isFirstStep=false;
}
if (!isWorking()) {
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- go out from the workcycle just after waiting");
break;
}
if (imageSeparateDetecting.empty()) {
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- imageSeparateDetecting is empty, continue");
continue;
}
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- start handling imageSeparateDetecting, img.size=%dx%d, img.data=0x%p",
imageSeparateDetecting.size().width, imageSeparateDetecting.size().height, (void*)imageSeparateDetecting.data);
int64 t1_detect=getTickCount();
cascadeInThread->detect(imageSeparateDetecting, objects);
/*cascadeInThread.detectMultiScale( imageSeparateDetecting, objects,
detectionBasedTracker.parameters.scaleFactor, detectionBasedTracker.parameters.minNeighbors, 0
|CV_HAAR_SCALE_IMAGE
,
min_objectSize,
max_objectSize
);
*/
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- end handling imageSeparateDetecting");
if (!isWorking()) {
LOGD("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- go out from the workcycle just after detecting");
break;
}
int64 t2_detect = getTickCount();
int64 dt_detect = t2_detect-t1_detect;
double dt_detect_ms=((double)dt_detect)/freq * 1000.0;
(void)(dt_detect_ms);
LOGI("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector() --- objects num==%d, t_ms=%.4f", (int)objects.size(), dt_detect_ms);
mtx_lock.lock();
if (!shouldObjectDetectingResultsBeForgot) {
resultDetect=objects;
isObjectDetectingReady=true;
} else { //shouldObjectDetectingResultsBeForgot==true
resultDetect.clear();
isObjectDetectingReady=false;
shouldObjectDetectingResultsBeForgot=false;
}
if(isWorking()) {
stateThread=STATE_THREAD_WORKING_SLEEPING;
}
mtx_lock.unlock();
objects.clear();
}// while(isWorking())
LOGI("DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector: Returning");
}
void cv::DetectionBasedTracker::SeparateDetectionWork::stop()
{
//FIXME: TODO: should add quickStop functionality
std::unique_lock<std::mutex> mtx_lock(mtx);
if (!isWorking()) {
mtx_lock.unlock();
LOGE("SimpleHighguiDemoCore::stop is called but the SimpleHighguiDemoCore pthread is not active");
stateThread = STATE_THREAD_STOPPING;
return;
}
stateThread=STATE_THREAD_STOPPING;
LOGD("DetectionBasedTracker::SeparateDetectionWork::stop: before going to sleep to wait for the signal from the workthread");
objectDetectorRun.notify_one();
objectDetectorThreadStartStop.wait(mtx_lock);
LOGD("DetectionBasedTracker::SeparateDetectionWork::stop: after receiving the signal from the workthread, stateThread=%d", (int)stateThread);
mtx_lock.unlock();
}
void cv::DetectionBasedTracker::SeparateDetectionWork::resetTracking()
{
LOGD("DetectionBasedTracker::SeparateDetectionWork::resetTracking");
std::unique_lock<std::mutex> mtx_lock(mtx);
if (stateThread == STATE_THREAD_WORKING_WITH_IMAGE) {
LOGD("DetectionBasedTracker::SeparateDetectionWork::resetTracking: since workthread is detecting objects at the moment, we should make cascadeInThread stop detecting and forget the detecting results");
shouldObjectDetectingResultsBeForgot=true;
//cascadeInThread.setStopFlag();//FIXME: TODO: this feature also should be contributed to OpenCV
} else {
LOGD("DetectionBasedTracker::SeparateDetectionWork::resetTracking: since workthread is NOT detecting objects at the moment, we should NOT make any additional actions");
}
resultDetect.clear();
isObjectDetectingReady=false;
mtx_lock.unlock();
}
bool cv::DetectionBasedTracker::SeparateDetectionWork::communicateWithDetectingThread(const Mat& imageGray, std::vector<Rect>& rectsWhereRegions)
{
static double freq = getTickFrequency();
bool shouldCommunicateWithDetectingThread = (stateThread==STATE_THREAD_WORKING_SLEEPING);
LOGD("DetectionBasedTracker::SeparateDetectionWork::communicateWithDetectingThread: shouldCommunicateWithDetectingThread=%d", (shouldCommunicateWithDetectingThread?1:0));
if (!shouldCommunicateWithDetectingThread) {
return false;
}
bool shouldHandleResult = false;
std::unique_lock<std::mutex> mtx_lock(mtx);
if (isObjectDetectingReady) {
shouldHandleResult=true;
rectsWhereRegions = resultDetect;
isObjectDetectingReady=false;
double lastBigDetectionDuration = 1000.0 * (((double)(getTickCount() - timeWhenDetectingThreadStartedWork )) / freq);
(void)(lastBigDetectionDuration);
LOGD("DetectionBasedTracker::SeparateDetectionWork::communicateWithDetectingThread: lastBigDetectionDuration=%f ms", (double)lastBigDetectionDuration);
}
bool shouldSendNewDataToWorkThread = true;
if (timeWhenDetectingThreadStartedWork > 0) {
double time_from_previous_launch_in_ms=1000.0 * (((double)(getTickCount() - timeWhenDetectingThreadStartedWork )) / freq); //the same formula as for lastBigDetectionDuration
shouldSendNewDataToWorkThread = (time_from_previous_launch_in_ms >= detectionBasedTracker.parameters.minDetectionPeriod);
LOGD("DetectionBasedTracker::SeparateDetectionWork::communicateWithDetectingThread: shouldSendNewDataToWorkThread was 1, now it is %d, since time_from_previous_launch_in_ms=%.2f, minDetectionPeriod=%d",
(shouldSendNewDataToWorkThread?1:0), time_from_previous_launch_in_ms, detectionBasedTracker.parameters.minDetectionPeriod);
}
if (shouldSendNewDataToWorkThread) {
imageSeparateDetecting.create(imageGray.size(), CV_8UC1);
imageGray.copyTo(imageSeparateDetecting);//may change imageSeparateDetecting ptr. But should not.
timeWhenDetectingThreadStartedWork = getTickCount() ;
objectDetectorRun.notify_one();
}
mtx_lock.unlock();
LOGD("DetectionBasedTracker::SeparateDetectionWork::communicateWithDetectingThread: result: shouldHandleResult=%d", (shouldHandleResult?1:0));
return shouldHandleResult;
}
cv::DetectionBasedTracker::Parameters::Parameters()
{
maxTrackLifetime = 5;
minDetectionPeriod = 0;
}
cv::DetectionBasedTracker::InnerParameters::InnerParameters()
{
numLastPositionsToTrack=4;
numStepsToWaitBeforeFirstShow=6;
numStepsToTrackWithoutDetectingIfObjectHasNotBeenShown=3;
numStepsToShowWithoutDetecting=3;
coeffTrackingWindowSize=2.0;
coeffObjectSizeToTrack=0.85f;
coeffObjectSpeedUsingInPrediction=0.8f;
}
cv::DetectionBasedTracker::DetectionBasedTracker(cv::Ptr<IDetector> mainDetector, cv::Ptr<IDetector> trackingDetector, const Parameters& params)
:separateDetectionWork(),
parameters(params),
innerParameters(),
numTrackedSteps(0),
cascadeForTracking(trackingDetector)
{
CV_Assert( (params.maxTrackLifetime >= 0)
// && mainDetector
&& trackingDetector );
if (mainDetector) {
Ptr<SeparateDetectionWork> tmp(new SeparateDetectionWork(*this, mainDetector, params));
separateDetectionWork.swap(tmp);
}
weightsPositionsSmoothing.push_back(1);
weightsSizesSmoothing.push_back(0.5);
weightsSizesSmoothing.push_back(0.3f);
weightsSizesSmoothing.push_back(0.2f);
}
cv::DetectionBasedTracker::~DetectionBasedTracker()
{
}
void DetectionBasedTracker::process(const Mat& imageGray)
{
CV_INSTRUMENT_REGION();
CV_Assert(imageGray.type()==CV_8UC1);
if ( separateDetectionWork && !separateDetectionWork->isWorking() ) {
separateDetectionWork->run();
}
static double freq = getTickFrequency();
static long long time_when_last_call_started=getTickCount();
{
double delta_time_from_prev_call=1000.0 * (((double)(getTickCount() - time_when_last_call_started)) / freq);
(void)(delta_time_from_prev_call);
LOGD("DetectionBasedTracker::process: time from the previous call is %f ms", (double)delta_time_from_prev_call);
time_when_last_call_started=getTickCount();
}
Mat imageDetect=imageGray;
std::vector<Rect> rectsWhereRegions;
bool shouldHandleResult=false;
if (separateDetectionWork) {
shouldHandleResult = separateDetectionWork->communicateWithDetectingThread(imageGray, rectsWhereRegions);
}
if (shouldHandleResult) {
LOGD("DetectionBasedTracker::process: get _rectsWhereRegions were got from resultDetect");
} else {
LOGD("DetectionBasedTracker::process: get _rectsWhereRegions from previous positions");
for(size_t i = 0; i < trackedObjects.size(); i++) {
size_t n = trackedObjects[i].lastPositions.size();
CV_Assert(n > 0);
Rect r = trackedObjects[i].lastPositions[n-1];
if(r.empty()) {
LOGE("DetectionBasedTracker::process: ERROR: ATTENTION: strange algorithm's behavior: trackedObjects[i].rect() is empty");
continue;
}
//correction by speed of rectangle
if (n > 1) {
Point2f center = centerRect(r);
Point2f center_prev = centerRect(trackedObjects[i].lastPositions[n-2]);
Point2f shift = (center - center_prev) * innerParameters.coeffObjectSpeedUsingInPrediction;
r.x += cvRound(shift.x);
r.y += cvRound(shift.y);
}
rectsWhereRegions.push_back(r);
}
}
LOGI("DetectionBasedTracker::process: tracked objects num==%d", (int)trackedObjects.size());
std::vector<Rect> detectedObjectsInRegions;
LOGD("DetectionBasedTracker::process: rectsWhereRegions.size()=%d", (int)rectsWhereRegions.size());
for(size_t i=0; i < rectsWhereRegions.size(); i++) {
Rect r = rectsWhereRegions[i];
detectInRegion(imageDetect, r, detectedObjectsInRegions);
}
LOGD("DetectionBasedTracker::process: detectedObjectsInRegions.size()=%d", (int)detectedObjectsInRegions.size());
updateTrackedObjects(detectedObjectsInRegions);
}
void cv::DetectionBasedTracker::getObjects(std::vector<cv::Rect>& result) const
{
result.clear();
for(size_t i=0; i < trackedObjects.size(); i++) {
Rect r=calcTrackedObjectPositionToShow((int)i);
if (r.empty()) {
continue;
}
result.push_back(r);
LOGD("DetectionBasedTracker::process: found a object with SIZE %d x %d, rect={%d, %d, %d x %d}", r.width, r.height, r.x, r.y, r.width, r.height);
}
}
void cv::DetectionBasedTracker::getObjects(std::vector<Object>& result) const
{
result.clear();
for(size_t i=0; i < trackedObjects.size(); i++) {
Rect r=calcTrackedObjectPositionToShow((int)i);
if (r.empty()) {
continue;
}
result.push_back(Object(r, trackedObjects[i].id));
LOGD("DetectionBasedTracker::process: found a object with SIZE %d x %d, rect={%d, %d, %d x %d}", r.width, r.height, r.x, r.y, r.width, r.height);
}
}
void cv::DetectionBasedTracker::getObjects(std::vector<ExtObject>& result) const
{
result.clear();
for(size_t i=0; i < trackedObjects.size(); i++) {
ObjectStatus status;
Rect r=calcTrackedObjectPositionToShow((int)i, status);
result.push_back(ExtObject(trackedObjects[i].id, r, status));
LOGD("DetectionBasedTracker::process: found a object with SIZE %d x %d, rect={%d, %d, %d x %d}, status = %d", r.width, r.height, r.x, r.y, r.width, r.height, (int)status);
}
}
bool cv::DetectionBasedTracker::run()
{
if (separateDetectionWork) {
return separateDetectionWork->run();
}
return false;
}
void cv::DetectionBasedTracker::stop()
{
if (separateDetectionWork) {
separateDetectionWork->stop();
}
}
void cv::DetectionBasedTracker::resetTracking()
{
if (separateDetectionWork) {
separateDetectionWork->resetTracking();
}
trackedObjects.clear();
}
void cv::DetectionBasedTracker::updateTrackedObjects(const std::vector<Rect>& detectedObjects)
{
enum {
NEW_RECTANGLE=-1,
INTERSECTED_RECTANGLE=-2
};
int N1=(int)trackedObjects.size();
int N2=(int)detectedObjects.size();
LOGD("DetectionBasedTracker::updateTrackedObjects: N1=%d, N2=%d", N1, N2);
for(int i=0; i < N1; i++) {
trackedObjects[i].numDetectedFrames++;
}
std::vector<int> correspondence(detectedObjects.size(), NEW_RECTANGLE);
correspondence.clear();
correspondence.resize(detectedObjects.size(), NEW_RECTANGLE);
for(int i=0; i < N1; i++) {
LOGD("DetectionBasedTracker::updateTrackedObjects: i=%d", i);
TrackedObject& curObject=trackedObjects[i];
int bestIndex=-1;
int bestArea=-1;
int numpositions=(int)curObject.lastPositions.size();
CV_Assert(numpositions > 0);
Rect prevRect=curObject.lastPositions[numpositions-1];
LOGD("DetectionBasedTracker::updateTrackedObjects: prevRect[%d]={%d, %d, %d x %d}", i, prevRect.x, prevRect.y, prevRect.width, prevRect.height);
for(int j=0; j < N2; j++) {
LOGD("DetectionBasedTracker::updateTrackedObjects: j=%d", j);
if (correspondence[j] >= 0) {
LOGD("DetectionBasedTracker::updateTrackedObjects: j=%d is rejected, because it has correspondence=%d", j, correspondence[j]);
continue;
}
if (correspondence[j] !=NEW_RECTANGLE) {
LOGD("DetectionBasedTracker::updateTrackedObjects: j=%d is rejected, because it is intersected with another rectangle", j);
continue;
}
LOGD("DetectionBasedTracker::updateTrackedObjects: detectedObjects[%d]={%d, %d, %d x %d}",
j, detectedObjects[j].x, detectedObjects[j].y, detectedObjects[j].width, detectedObjects[j].height);
Rect r=prevRect & detectedObjects[j];
if ( (r.width > 0) && (r.height > 0) ) {
LOGD("DetectionBasedTracker::updateTrackedObjects: There is intersection between prevRect and detectedRect, r={%d, %d, %d x %d}",
r.x, r.y, r.width, r.height);
correspondence[j]=INTERSECTED_RECTANGLE;
if ( r.area() > bestArea) {
LOGD("DetectionBasedTracker::updateTrackedObjects: The area of intersection is %d, it is better than bestArea=%d", r.area(), bestArea);
bestIndex=j;
bestArea=r.area();
}
}
}
if (bestIndex >= 0) {
LOGD("DetectionBasedTracker::updateTrackedObjects: The best correspondence for i=%d is j=%d", i, bestIndex);
correspondence[bestIndex]=i;
for(int j=0; j < N2; j++) {
if (correspondence[j] >= 0)
continue;
Rect r=detectedObjects[j] & detectedObjects[bestIndex];
if ( (r.width > 0) && (r.height > 0) ) {
LOGD("DetectionBasedTracker::updateTrackedObjects: Found intersection between "
"rectangles j=%d and bestIndex=%d, rectangle j=%d is marked as intersected", j, bestIndex, j);
correspondence[j]=INTERSECTED_RECTANGLE;
}
}
} else {
LOGD("DetectionBasedTracker::updateTrackedObjects: There is no correspondence for i=%d ", i);
curObject.numFramesNotDetected++;
}
}
LOGD("DetectionBasedTracker::updateTrackedObjects: start second cycle");
for(int j=0; j < N2; j++) {
LOGD("DetectionBasedTracker::updateTrackedObjects: j=%d", j);
int i=correspondence[j];
if (i >= 0) {//add position
LOGD("DetectionBasedTracker::updateTrackedObjects: add position");
trackedObjects[i].lastPositions.push_back(detectedObjects[j]);
while ((int)trackedObjects[i].lastPositions.size() > (int) innerParameters.numLastPositionsToTrack) {
trackedObjects[i].lastPositions.erase(trackedObjects[i].lastPositions.begin());
}
trackedObjects[i].numFramesNotDetected=0;
} else if (i==NEW_RECTANGLE){ //new object
LOGD("DetectionBasedTracker::updateTrackedObjects: new object");
trackedObjects.push_back(detectedObjects[j]);
} else {
LOGD("DetectionBasedTracker::updateTrackedObjects: was auxiliary intersection");
}
}
std::vector<TrackedObject>::iterator it=trackedObjects.begin();
while( it != trackedObjects.end() ) {
if ( (it->numFramesNotDetected > parameters.maxTrackLifetime)
||
(
(it->numDetectedFrames <= innerParameters.numStepsToWaitBeforeFirstShow)
&&
(it->numFramesNotDetected > innerParameters.numStepsToTrackWithoutDetectingIfObjectHasNotBeenShown)
)
)
{
int numpos=(int)it->lastPositions.size();
CV_Assert(numpos > 0);
Rect r = it->lastPositions[numpos-1];
(void)(r);
LOGD("DetectionBasedTracker::updateTrackedObjects: deleted object {%d, %d, %d x %d}",
r.x, r.y, r.width, r.height);
it=trackedObjects.erase(it);
} else {
it++;
}
}
}
int cv::DetectionBasedTracker::addObject(const Rect& location)
{
LOGD("DetectionBasedTracker::addObject: new object {%d, %d %dx%d}",location.x, location.y, location.width, location.height);
trackedObjects.push_back(TrackedObject(location));
int newId = trackedObjects.back().id;
LOGD("DetectionBasedTracker::addObject: newId = %d", newId);
return newId;
}
Rect cv::DetectionBasedTracker::calcTrackedObjectPositionToShow(int i) const
{
ObjectStatus status;
return calcTrackedObjectPositionToShow(i, status);
}
Rect cv::DetectionBasedTracker::calcTrackedObjectPositionToShow(int i, ObjectStatus& status) const
{
if ( (i < 0) || (i >= (int)trackedObjects.size()) ) {
LOGE("DetectionBasedTracker::calcTrackedObjectPositionToShow: ERROR: wrong i=%d", i);
status = WRONG_OBJECT;
return Rect();
}
if (trackedObjects[i].numDetectedFrames <= innerParameters.numStepsToWaitBeforeFirstShow){
LOGI("DetectionBasedTracker::calcTrackedObjectPositionToShow: trackedObjects[%d].numDetectedFrames=%d <= numStepsToWaitBeforeFirstShow=%d --- return empty Rect()",
i, trackedObjects[i].numDetectedFrames, innerParameters.numStepsToWaitBeforeFirstShow);
status = DETECTED_NOT_SHOWN_YET;
return Rect();
}
if (trackedObjects[i].numFramesNotDetected > innerParameters.numStepsToShowWithoutDetecting) {
status = DETECTED_TEMPORARY_LOST;
return Rect();
}
const TrackedObject::PositionsVector& lastPositions=trackedObjects[i].lastPositions;
int N=(int)lastPositions.size();
if (N<=0) {
LOGE("DetectionBasedTracker::calcTrackedObjectPositionToShow: ERROR: no positions for i=%d", i);
status = WRONG_OBJECT;
return Rect();
}
int Nsize=std::min(N, (int)weightsSizesSmoothing.size());
int Ncenter= std::min(N, (int)weightsPositionsSmoothing.size());
Point2f center;
double w=0, h=0;
if (Nsize > 0) {
double sum=0;
for(int j=0; j < Nsize; j++) {
int k=N-j-1;
w += lastPositions[k].width * weightsSizesSmoothing[j];
h += lastPositions[k].height * weightsSizesSmoothing[j];
sum+=weightsSizesSmoothing[j];
}
w /= sum;
h /= sum;
} else {
w=lastPositions[N-1].width;
h=lastPositions[N-1].height;
}
if (Ncenter > 0) {
double sum=0;
for(int j=0; j < Ncenter; j++) {
int k=N-j-1;
Point tl(lastPositions[k].tl());
Point br(lastPositions[k].br());
Point2f c1;
c1=tl;
c1=c1* 0.5f;
Point2f c2;
c2=br;
c2=c2*0.5f;
c1=c1+c2;
center=center+ (c1 * weightsPositionsSmoothing[j]);
sum+=weightsPositionsSmoothing[j];
}
center *= (float)(1 / sum);
} else {
int k=N-1;
Point tl(lastPositions[k].tl());
Point br(lastPositions[k].br());
Point2f c1;
c1=tl;
c1=c1* 0.5f;
Point2f c2;
c2=br;
c2=c2*0.5f;
center=c1+c2;
}
Point2f tl=center-Point2f((float)w*0.5f,(float)h*0.5f);
Rect res(cvRound(tl.x), cvRound(tl.y), cvRound(w), cvRound(h));
LOGD("DetectionBasedTracker::calcTrackedObjectPositionToShow: Result for i=%d: {%d, %d, %d x %d}", i, res.x, res.y, res.width, res.height);
status = DETECTED;
return res;
}
void cv::DetectionBasedTracker::detectInRegion(const Mat& img, const Rect& r, std::vector<Rect>& detectedObjectsInRegions)
{
Rect r0(Point(), img.size());
Rect r1 = scale_rect(r, innerParameters.coeffTrackingWindowSize);
r1 = r1 & r0;
if ( (r1.width <=0) || (r1.height <= 0) ) {
LOGD("DetectionBasedTracker::detectInRegion: Empty intersection");
return;
}
int d = cvRound(std::min(r.width, r.height) * innerParameters.coeffObjectSizeToTrack);
std::vector<Rect> tmpobjects;
Mat img1(img, r1);//subimage for rectangle -- without data copying
LOGD("DetectionBasedTracker::detectInRegion: img1.size()=%d x %d, d=%d",
img1.size().width, img1.size().height, d);
cascadeForTracking->setMinObjectSize(Size(d, d));
cascadeForTracking->detect(img1, tmpobjects);
/*
detectMultiScale( img1, tmpobjects,
parameters.scaleFactor, parameters.minNeighbors, 0
|CV_HAAR_FIND_BIGGEST_OBJECT
|CV_HAAR_SCALE_IMAGE
,
Size(d,d),
max_objectSize
);*/
for(size_t i=0; i < tmpobjects.size(); i++) {
Rect curres(tmpobjects[i].tl() + r1.tl(), tmpobjects[i].size());
detectedObjectsInRegions.push_back(curres);
}
}
bool cv::DetectionBasedTracker::setParameters(const Parameters& params)
{
if ( params.maxTrackLifetime < 0 )
{
LOGE("DetectionBasedTracker::setParameters: ERROR: wrong parameters value");
return false;
}
if (separateDetectionWork) {
separateDetectionWork->setParameters(params);
}
parameters=params;
return true;
}
const cv::DetectionBasedTracker::Parameters& DetectionBasedTracker::getParameters() const
{
return parameters;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,661 +0,0 @@
///////////////////////////// OpenCL kernels for face detection //////////////////////////////
////////////////////////////// see the opencv/doc/license.txt ///////////////////////////////
//
// the code has been derived from the OpenCL Haar cascade kernel by
//
// Niko Li, newlife20080214@gmail.com
// Wang Weiyan, wangweiyanster@gmail.com
// Jia Haipeng, jiahaipeng95@gmail.com
// Nathan, liujun@multicorewareinc.com
// Peng Xiao, pengxiao@outlook.com
// Erping Pang, erping@multicorewareinc.com
//
#ifdef HAAR
typedef struct __attribute__((aligned(4))) OptHaarFeature
{
int4 ofs[3] __attribute__((aligned (4)));
float4 weight __attribute__((aligned (4)));
}
OptHaarFeature;
#endif
#ifdef LBP
typedef struct __attribute__((aligned(4))) OptLBPFeature
{
int16 ofs __attribute__((aligned (4)));
}
OptLBPFeature;
#endif
typedef struct __attribute__((aligned(4))) Stump
{
float4 st __attribute__((aligned (4)));
}
Stump;
typedef struct __attribute__((aligned(4))) Node
{
int4 n __attribute__((aligned (4)));
}
Node;
typedef struct __attribute__((aligned (4))) Stage
{
int first __attribute__((aligned (4)));
int ntrees __attribute__((aligned (4)));
float threshold __attribute__((aligned (4)));
}
Stage;
typedef struct __attribute__((aligned (4))) ScaleData
{
float scale __attribute__((aligned (4)));
int szi_width __attribute__((aligned (4)));
int szi_height __attribute__((aligned (4)));
int layer_ofs __attribute__((aligned (4)));
int ystep __attribute__((aligned (4)));
}
ScaleData;
#ifndef SUM_BUF_SIZE
#define SUM_BUF_SIZE 0
#endif
#ifndef NODE_COUNT
#define NODE_COUNT 1
#endif
#ifdef HAAR
__kernel __attribute__((reqd_work_group_size(LOCAL_SIZE_X,LOCAL_SIZE_Y,1)))
void runHaarClassifier(
int nscales, __global const ScaleData* scaleData,
__global const int* sum,
int _sumstep, int sumoffset,
__global const OptHaarFeature* optfeatures,
__global const Stage* stages,
__global const Node* nodes,
__global const float* leaves0,
volatile __global int* facepos,
int4 normrect, int sqofs, int2 windowsize)
{
int lx = get_local_id(0);
int ly = get_local_id(1);
int groupIdx = get_group_id(0);
int i, ngroups = get_global_size(0)/LOCAL_SIZE_X;
int scaleIdx, tileIdx, stageIdx;
int sumstep = (int)(_sumstep/sizeof(int));
int4 nofs0 = (int4)(mad24(normrect.y, sumstep, normrect.x),
mad24(normrect.y, sumstep, normrect.x + normrect.z),
mad24(normrect.y + normrect.w, sumstep, normrect.x),
mad24(normrect.y + normrect.w, sumstep, normrect.x + normrect.z));
int normarea = normrect.z * normrect.w;
float invarea = 1.f/normarea;
int lidx = ly*LOCAL_SIZE_X + lx;
#if SUM_BUF_SIZE > 0
int4 nofs = (int4)(mad24(normrect.y, SUM_BUF_STEP, normrect.x),
mad24(normrect.y, SUM_BUF_STEP, normrect.x + normrect.z),
mad24(normrect.y + normrect.w, SUM_BUF_STEP, normrect.x),
mad24(normrect.y + normrect.w, SUM_BUF_STEP, normrect.x + normrect.z));
#else
int4 nofs = nofs0;
#endif
#define LOCAL_SIZE (LOCAL_SIZE_X*LOCAL_SIZE_Y)
__local int lstore[SUM_BUF_SIZE + LOCAL_SIZE*5/2+1];
#if SUM_BUF_SIZE > 0
__local int* ibuf = lstore;
__local int* lcount = ibuf + SUM_BUF_SIZE;
#else
__local int* lcount = lstore;
#endif
__local float* lnf = (__local float*)(lcount + 1);
__local float* lpartsum = lnf + LOCAL_SIZE;
__local short* lbuf = (__local short*)(lpartsum + LOCAL_SIZE);
for( scaleIdx = nscales-1; scaleIdx >= 0; scaleIdx-- )
{
__global const ScaleData* s = scaleData + scaleIdx;
int ystep = s->ystep;
int2 worksize = (int2)(max(s->szi_width - windowsize.x, 0), max(s->szi_height - windowsize.y, 0));
int2 ntiles = (int2)((worksize.x + LOCAL_SIZE_X-1)/LOCAL_SIZE_X,
(worksize.y + LOCAL_SIZE_Y-1)/LOCAL_SIZE_Y);
int totalTiles = ntiles.x*ntiles.y;
for( tileIdx = groupIdx; tileIdx < totalTiles; tileIdx += ngroups )
{
int ix0 = (tileIdx % ntiles.x)*LOCAL_SIZE_X;
int iy0 = (tileIdx / ntiles.x)*LOCAL_SIZE_Y;
int ix = lx, iy = ly;
__global const int* psum0 = sum + mad24(iy0, sumstep, ix0) + s->layer_ofs;
__global const int* psum1 = psum0 + mad24(iy, sumstep, ix);
if( ix0 >= worksize.x || iy0 >= worksize.y )
continue;
#if SUM_BUF_SIZE > 0
for( i = lidx*4; i < SUM_BUF_SIZE; i += LOCAL_SIZE_X*LOCAL_SIZE_Y*4 )
{
int dy = i/SUM_BUF_STEP, dx = i - dy*SUM_BUF_STEP;
vstore4(vload4(0, psum0 + mad24(dy, sumstep, dx)), 0, ibuf+i);
}
#endif
if( lidx == 0 )
lcount[0] = 0;
barrier(CLK_LOCAL_MEM_FENCE);
if( ix0 + ix < worksize.x && iy0 + iy < worksize.y )
{
#if NODE_COUNT==1
__global const Stump* stump = (__global const Stump*)nodes;
#else
__global const Node* node = nodes;
__global const float* leaves = leaves0;
#endif
#if SUM_BUF_SIZE > 0
__local const int* psum = ibuf + mad24(iy, SUM_BUF_STEP, ix);
#else
__global const int* psum = psum1;
#endif
__global const int* psqsum = (__global const int*)(psum1 + sqofs);
float sval = (psum[nofs.x] - psum[nofs.y] - psum[nofs.z] + psum[nofs.w])*invarea;
float sqval = (psqsum[nofs0.x] - psqsum[nofs0.y] - psqsum[nofs0.z] + psqsum[nofs0.w])*invarea;
float nf = (float)normarea * sqrt(max(sqval - sval * sval, 0.f));
nf = nf > 0 ? nf : 1.f;
for( stageIdx = 0; stageIdx < SPLIT_STAGE; stageIdx++ )
{
int ntrees = stages[stageIdx].ntrees;
float s = 0.f;
#if NODE_COUNT==1
for( i = 0; i < ntrees; i++ )
{
float4 st = stump[i].st;
__global const OptHaarFeature* f = optfeatures + as_int(st.x);
float4 weight = f->weight;
int4 ofs = f->ofs[0];
sval = (psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w])*weight.x;
ofs = f->ofs[1];
sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
if( weight.z > 0 )
{
ofs = f->ofs[2];
sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
}
s += (sval < st.y*nf) ? st.z : st.w;
}
stump += ntrees;
#else
for( i = 0; i < ntrees; i++, node += NODE_COUNT, leaves += NODE_COUNT+1 )
{
int idx = 0;
do
{
int4 n = node[idx].n;
__global const OptHaarFeature* f = optfeatures + n.x;
float4 weight = f->weight;
int4 ofs = f->ofs[0];
sval = (psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w])*weight.x;
ofs = f->ofs[1];
sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
if( weight.z > 0 )
{
ofs = f->ofs[2];
sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
}
idx = (sval < as_float(n.y)*nf) ? n.z : n.w;
}
while(idx > 0);
s += leaves[-idx];
}
#endif
if( s < stages[stageIdx].threshold )
break;
}
if( stageIdx == SPLIT_STAGE && (ystep == 1 || ((ix | iy) & 1) == 0) )
{
int count = atomic_inc(lcount);
lbuf[count] = (int)(ix | (iy << 8));
lnf[count] = nf;
}
}
for( stageIdx = SPLIT_STAGE; stageIdx < N_STAGES; stageIdx++ )
{
barrier(CLK_LOCAL_MEM_FENCE);
int nrects = lcount[0];
if( nrects == 0 )
break;
barrier(CLK_LOCAL_MEM_FENCE);
if( lidx == 0 )
lcount[0] = 0;
{
#if NODE_COUNT == 1
__global const Stump* stump = (__global const Stump*)nodes + stages[stageIdx].first;
#else
__global const Node* node = nodes + stages[stageIdx].first*NODE_COUNT;
__global const float* leaves = leaves0 + stages[stageIdx].first*(NODE_COUNT+1);
#endif
int nparts = LOCAL_SIZE / nrects;
int ntrees = stages[stageIdx].ntrees;
int ntrees_p = (ntrees + nparts - 1)/nparts;
int nr = lidx / nparts;
int partidx = -1, idxval = 0;
float partsum = 0.f, nf = 0.f;
if( nr < nrects )
{
partidx = lidx % nparts;
idxval = lbuf[nr];
nf = lnf[nr];
{
int ntrees0 = ntrees_p*partidx;
int ntrees1 = min(ntrees0 + ntrees_p, ntrees);
int ix1 = idxval & 255, iy1 = idxval >> 8;
#if SUM_BUF_SIZE > 0
__local const int* psum = ibuf + mad24(iy1, SUM_BUF_STEP, ix1);
#else
__global const int* psum = psum0 + mad24(iy1, sumstep, ix1);
#endif
#if NODE_COUNT == 1
for( i = ntrees0; i < ntrees1; i++ )
{
float4 st = stump[i].st;
__global const OptHaarFeature* f = optfeatures + as_int(st.x);
float4 weight = f->weight;
int4 ofs = f->ofs[0];
float sval = (psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w])*weight.x;
ofs = f->ofs[1];
sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
//if( weight.z > 0 )
if( fabs(weight.z) > 0 )
{
ofs = f->ofs[2];
sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
}
partsum += (sval < st.y*nf) ? st.z : st.w;
}
#else
for( i = ntrees0; i < ntrees1; i++ )
{
int idx = 0;
do
{
int4 n = node[i*2 + idx].n;
__global const OptHaarFeature* f = optfeatures + n.x;
float4 weight = f->weight;
int4 ofs = f->ofs[0];
float sval = (psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w])*weight.x;
ofs = f->ofs[1];
sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
if( weight.z > 0 )
{
ofs = f->ofs[2];
sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
}
idx = (sval < as_float(n.y)*nf) ? n.z : n.w;
}
while(idx > 0);
partsum += leaves[i*3-idx];
}
#endif
}
}
lpartsum[lidx] = partsum;
barrier(CLK_LOCAL_MEM_FENCE);
if( partidx == 0 )
{
float s = lpartsum[nr*nparts];
for( i = 1; i < nparts; i++ )
s += lpartsum[i + nr*nparts];
if( s >= stages[stageIdx].threshold )
{
int count = atomic_inc(lcount);
lbuf[count] = idxval;
lnf[count] = nf;
}
}
}
}
barrier(CLK_LOCAL_MEM_FENCE);
if( stageIdx == N_STAGES )
{
int nrects = lcount[0];
if( lidx < nrects )
{
int nfaces = atomic_inc(facepos);
if( nfaces < MAX_FACES )
{
volatile __global int* face = facepos + 1 + nfaces*3;
int val = lbuf[lidx];
face[0] = scaleIdx;
face[1] = ix0 + (val & 255);
face[2] = iy0 + (val >> 8);
}
}
}
}
}
}
#endif
#ifdef LBP
#undef CALC_SUM_OFS_
#define CALC_SUM_OFS_(p0, p1, p2, p3, ptr) \
((ptr)[p0] - (ptr)[p1] - (ptr)[p2] + (ptr)[p3])
__kernel void runLBPClassifierStumpSimple(
int nscales, __global const ScaleData* scaleData,
__global const int* sum,
int _sumstep, int sumoffset,
__global const OptLBPFeature* optfeatures,
__global const Stage* stages,
__global const Stump* stumps,
__global const int* bitsets,
int bitsetSize,
volatile __global int* facepos,
int2 windowsize)
{
int lx = get_local_id(0);
int ly = get_local_id(1);
int local_size_x = get_local_size(0);
int local_size_y = get_local_size(1);
int groupIdx = get_group_id(1)*get_num_groups(0) + get_group_id(0);
int ngroups = get_num_groups(0)*get_num_groups(1);
int scaleIdx, tileIdx, stageIdx;
int sumstep = (int)(_sumstep/sizeof(int));
for( scaleIdx = nscales-1; scaleIdx >= 0; scaleIdx-- )
{
__global const ScaleData* s = scaleData + scaleIdx;
int ystep = s->ystep;
int2 worksize = (int2)(max(s->szi_width - windowsize.x, 0), max(s->szi_height - windowsize.y, 0));
int2 ntiles = (int2)((worksize.x/ystep + local_size_x-1)/local_size_x,
(worksize.y/ystep + local_size_y-1)/local_size_y);
int totalTiles = ntiles.x*ntiles.y;
for( tileIdx = groupIdx; tileIdx < totalTiles; tileIdx += ngroups )
{
int iy = mad24((tileIdx / ntiles.x), local_size_y, ly) * ystep;
int ix = mad24((tileIdx % ntiles.x), local_size_x, lx) * ystep;
if( ix < worksize.x && iy < worksize.y )
{
__global const int* p = sum + mad24(iy, sumstep, ix) + s->layer_ofs;
__global const Stump* stump = stumps;
__global const int* bitset = bitsets;
for( stageIdx = 0; stageIdx < N_STAGES; stageIdx++ )
{
int i, ntrees = stages[stageIdx].ntrees;
float s = 0.f;
for( i = 0; i < ntrees; i++, stump++, bitset += bitsetSize )
{
float4 st = stump->st;
__global const OptLBPFeature* f = optfeatures + as_int(st.x);
int16 ofs = f->ofs;
int cval = CALC_SUM_OFS_( ofs.s5, ofs.s6, ofs.s9, ofs.sa, p );
int mask, idx = (CALC_SUM_OFS_( ofs.s0, ofs.s1, ofs.s4, ofs.s5, p ) >= cval ? 4 : 0); // 0
idx |= (CALC_SUM_OFS_( ofs.s1, ofs.s2, ofs.s5, ofs.s6, p ) >= cval ? 2 : 0); // 1
idx |= (CALC_SUM_OFS_( ofs.s2, ofs.s3, ofs.s6, ofs.s7, p ) >= cval ? 1 : 0); // 2
mask = (CALC_SUM_OFS_( ofs.s6, ofs.s7, ofs.sa, ofs.sb, p ) >= cval ? 16 : 0); // 5
mask |= (CALC_SUM_OFS_( ofs.sa, ofs.sb, ofs.se, ofs.sf, p ) >= cval ? 8 : 0); // 8
mask |= (CALC_SUM_OFS_( ofs.s9, ofs.sa, ofs.sd, ofs.se, p ) >= cval ? 4 : 0); // 7
mask |= (CALC_SUM_OFS_( ofs.s8, ofs.s9, ofs.sc, ofs.sd, p ) >= cval ? 2 : 0); // 6
mask |= (CALC_SUM_OFS_( ofs.s4, ofs.s5, ofs.s8, ofs.s9, p ) >= cval ? 1 : 0); // 7
s += (bitset[idx] & (1 << mask)) ? st.z : st.w;
}
if( s < stages[stageIdx].threshold )
break;
}
if( stageIdx == N_STAGES )
{
int nfaces = atomic_inc(facepos);
if( nfaces < MAX_FACES )
{
volatile __global int* face = facepos + 1 + nfaces*3;
face[0] = scaleIdx;
face[1] = ix;
face[2] = iy;
}
}
}
}
}
}
__kernel __attribute__((reqd_work_group_size(LOCAL_SIZE_X,LOCAL_SIZE_Y,1)))
void runLBPClassifierStump(
int nscales, __global const ScaleData* scaleData,
__global const int* sum,
int _sumstep, int sumoffset,
__global const OptLBPFeature* optfeatures,
__global const Stage* stages,
__global const Stump* stumps,
__global const int* bitsets,
int bitsetSize,
volatile __global int* facepos,
int2 windowsize)
{
int lx = get_local_id(0);
int ly = get_local_id(1);
int groupIdx = get_group_id(0);
int i, ngroups = get_global_size(0)/LOCAL_SIZE_X;
int scaleIdx, tileIdx, stageIdx;
int sumstep = (int)(_sumstep/sizeof(int));
int lidx = ly*LOCAL_SIZE_X + lx;
#define LOCAL_SIZE (LOCAL_SIZE_X*LOCAL_SIZE_Y)
__local int lstore[SUM_BUF_SIZE + LOCAL_SIZE*3/2+1];
#if SUM_BUF_SIZE > 0
__local int* ibuf = lstore;
__local int* lcount = ibuf + SUM_BUF_SIZE;
#else
__local int* lcount = lstore;
#endif
__local float* lpartsum = (__local float*)(lcount + 1);
__local short* lbuf = (__local short*)(lpartsum + LOCAL_SIZE);
for( scaleIdx = nscales-1; scaleIdx >= 0; scaleIdx-- )
{
__global const ScaleData* s = scaleData + scaleIdx;
int ystep = s->ystep;
int2 worksize = (int2)(max(s->szi_width - windowsize.x, 0), max(s->szi_height - windowsize.y, 0));
int2 ntiles = (int2)((worksize.x + LOCAL_SIZE_X-1)/LOCAL_SIZE_X,
(worksize.y + LOCAL_SIZE_Y-1)/LOCAL_SIZE_Y);
int totalTiles = ntiles.x*ntiles.y;
for( tileIdx = groupIdx; tileIdx < totalTiles; tileIdx += ngroups )
{
int ix0 = (tileIdx % ntiles.x)*LOCAL_SIZE_X;
int iy0 = (tileIdx / ntiles.x)*LOCAL_SIZE_Y;
int ix = lx, iy = ly;
__global const int* psum0 = sum + mad24(iy0, sumstep, ix0) + s->layer_ofs;
if( ix0 >= worksize.x || iy0 >= worksize.y )
continue;
#if SUM_BUF_SIZE > 0
for( i = lidx*4; i < SUM_BUF_SIZE; i += LOCAL_SIZE_X*LOCAL_SIZE_Y*4 )
{
int dy = i/SUM_BUF_STEP, dx = i - dy*SUM_BUF_STEP;
vstore4(vload4(0, psum0 + mad24(dy, sumstep, dx)), 0, ibuf+i);
}
barrier(CLK_LOCAL_MEM_FENCE);
#endif
if( lidx == 0 )
lcount[0] = 0;
barrier(CLK_LOCAL_MEM_FENCE);
if( ix0 + ix < worksize.x && iy0 + iy < worksize.y )
{
__global const Stump* stump = stumps;
__global const int* bitset = bitsets;
#if SUM_BUF_SIZE > 0
__local const int* p = ibuf + mad24(iy, SUM_BUF_STEP, ix);
#else
__global const int* p = psum0 + mad24(iy, sumstep, ix);
#endif
for( stageIdx = 0; stageIdx < SPLIT_STAGE; stageIdx++ )
{
int ntrees = stages[stageIdx].ntrees;
float s = 0.f;
for( i = 0; i < ntrees; i++, stump++, bitset += bitsetSize )
{
float4 st = stump->st;
__global const OptLBPFeature* f = optfeatures + as_int(st.x);
int16 ofs = f->ofs;
int cval = CALC_SUM_OFS_( ofs.s5, ofs.s6, ofs.s9, ofs.sa, p );
int mask, idx = (CALC_SUM_OFS_( ofs.s0, ofs.s1, ofs.s4, ofs.s5, p ) >= cval ? 4 : 0); // 0
idx |= (CALC_SUM_OFS_( ofs.s1, ofs.s2, ofs.s5, ofs.s6, p ) >= cval ? 2 : 0); // 1
idx |= (CALC_SUM_OFS_( ofs.s2, ofs.s3, ofs.s6, ofs.s7, p ) >= cval ? 1 : 0); // 2
mask = (CALC_SUM_OFS_( ofs.s6, ofs.s7, ofs.sa, ofs.sb, p ) >= cval ? 16 : 0); // 5
mask |= (CALC_SUM_OFS_( ofs.sa, ofs.sb, ofs.se, ofs.sf, p ) >= cval ? 8 : 0); // 8
mask |= (CALC_SUM_OFS_( ofs.s9, ofs.sa, ofs.sd, ofs.se, p ) >= cval ? 4 : 0); // 7
mask |= (CALC_SUM_OFS_( ofs.s8, ofs.s9, ofs.sc, ofs.sd, p ) >= cval ? 2 : 0); // 6
mask |= (CALC_SUM_OFS_( ofs.s4, ofs.s5, ofs.s8, ofs.s9, p ) >= cval ? 1 : 0); // 7
s += (bitset[idx] & (1 << mask)) ? st.z : st.w;
}
if( s < stages[stageIdx].threshold )
break;
}
if( stageIdx == SPLIT_STAGE && (ystep == 1 || ((ix | iy) & 1) == 0) )
{
int count = atomic_inc(lcount);
lbuf[count] = (int)(ix | (iy << 8));
}
}
for( stageIdx = SPLIT_STAGE; stageIdx < N_STAGES; stageIdx++ )
{
int nrects = lcount[0];
barrier(CLK_LOCAL_MEM_FENCE);
if( nrects == 0 )
break;
if( lidx == 0 )
lcount[0] = 0;
{
__global const Stump* stump = stumps + stages[stageIdx].first;
__global const int* bitset = bitsets + stages[stageIdx].first*bitsetSize;
int nparts = LOCAL_SIZE / nrects;
int ntrees = stages[stageIdx].ntrees;
int ntrees_p = (ntrees + nparts - 1)/nparts;
int nr = lidx / nparts;
int partidx = -1, idxval = 0;
float partsum = 0.f, nf = 0.f;
if( nr < nrects )
{
partidx = lidx % nparts;
idxval = lbuf[nr];
{
int ntrees0 = ntrees_p*partidx;
int ntrees1 = min(ntrees0 + ntrees_p, ntrees);
int ix1 = idxval & 255, iy1 = idxval >> 8;
#if SUM_BUF_SIZE > 0
__local const int* p = ibuf + mad24(iy1, SUM_BUF_STEP, ix1);
#else
__global const int* p = psum0 + mad24(iy1, sumstep, ix1);
#endif
for( i = ntrees0; i < ntrees1; i++ )
{
float4 st = stump[i].st;
__global const OptLBPFeature* f = optfeatures + as_int(st.x);
int16 ofs = f->ofs;
#define CALC_SUM_OFS_(p0, p1, p2, p3, ptr) \
((ptr)[p0] - (ptr)[p1] - (ptr)[p2] + (ptr)[p3])
int cval = CALC_SUM_OFS_( ofs.s5, ofs.s6, ofs.s9, ofs.sa, p );
int mask, idx = (CALC_SUM_OFS_( ofs.s0, ofs.s1, ofs.s4, ofs.s5, p ) >= cval ? 4 : 0); // 0
idx |= (CALC_SUM_OFS_( ofs.s1, ofs.s2, ofs.s5, ofs.s6, p ) >= cval ? 2 : 0); // 1
idx |= (CALC_SUM_OFS_( ofs.s2, ofs.s3, ofs.s6, ofs.s7, p ) >= cval ? 1 : 0); // 2
mask = (CALC_SUM_OFS_( ofs.s6, ofs.s7, ofs.sa, ofs.sb, p ) >= cval ? 16 : 0); // 5
mask |= (CALC_SUM_OFS_( ofs.sa, ofs.sb, ofs.se, ofs.sf, p ) >= cval ? 8 : 0); // 8
mask |= (CALC_SUM_OFS_( ofs.s9, ofs.sa, ofs.sd, ofs.se, p ) >= cval ? 4 : 0); // 7
mask |= (CALC_SUM_OFS_( ofs.s8, ofs.s9, ofs.sc, ofs.sd, p ) >= cval ? 2 : 0); // 6
mask |= (CALC_SUM_OFS_( ofs.s4, ofs.s5, ofs.s8, ofs.s9, p ) >= cval ? 1 : 0); // 7
partsum += (bitset[i*bitsetSize + idx] & (1 << mask)) ? st.z : st.w;
}
}
}
lpartsum[lidx] = partsum;
barrier(CLK_LOCAL_MEM_FENCE);
if( partidx == 0 )
{
float s = lpartsum[nr*nparts];
for( i = 1; i < nparts; i++ )
s += lpartsum[i + nr*nparts];
if( s >= stages[stageIdx].threshold )
{
int count = atomic_inc(lcount);
lbuf[count] = idxval;
}
}
}
}
barrier(CLK_LOCAL_MEM_FENCE);
if( stageIdx == N_STAGES )
{
int nrects = lcount[0];
if( lidx < nrects )
{
int nfaces = atomic_inc(facepos);
if( nfaces < MAX_FACES )
{
volatile __global int* face = facepos + 1 + nfaces*3;
int val = lbuf[lidx];
face[0] = scaleIdx;
face[1] = ix0 + (val & 255);
face[2] = iy0 + (val >> 8);
}
}
}
}
}
}
#endif

View File

@ -1,633 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Wenju He, wenju@multicorewareinc.com
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#define CELL_WIDTH 8
#define CELL_HEIGHT 8
#define CELLS_PER_BLOCK_X 2
#define CELLS_PER_BLOCK_Y 2
#define NTHREADS 256
#define CV_PI_F M_PI_F
#ifdef INTEL_DEVICE
#define QANGLE_TYPE int
#define QANGLE_TYPE2 int2
#else
#define QANGLE_TYPE uchar
#define QANGLE_TYPE2 uchar2
#endif
//----------------------------------------------------------------------------
// Histogram computation
// 12 threads for a cell, 12x4 threads per block
// Use pre-computed gaussian and interp_weight lookup tables
__kernel void compute_hists_lut_kernel(
const int cblock_stride_x, const int cblock_stride_y,
const int cnbins, const int cblock_hist_size, const int img_block_width,
const int blocks_in_group, const int blocks_total,
const int grad_quadstep, const int qangle_step,
__global const float* grad, __global const QANGLE_TYPE* qangle,
__global const float* gauss_w_lut,
__global float* block_hists, __local float* smem)
{
const int lx = get_local_id(0);
const int lp = lx / 24; /* local group id */
const int gid = get_group_id(0) * blocks_in_group + lp;/* global group id */
const int gidY = gid / img_block_width;
const int gidX = gid - gidY * img_block_width;
const int lidX = lx - lp * 24;
const int lidY = get_local_id(1);
const int cell_x = lidX / 12;
const int cell_y = lidY;
const int cell_thread_x = lidX - cell_x * 12;
__local float* hists = smem + lp * cnbins * (CELLS_PER_BLOCK_X *
CELLS_PER_BLOCK_Y * 12 + CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y);
__local float* final_hist = hists + cnbins *
(CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y * 12);
const int offset_x = gidX * cblock_stride_x + (cell_x << 2) + cell_thread_x;
const int offset_y = gidY * cblock_stride_y + (cell_y << 2);
__global const float* grad_ptr = (gid < blocks_total) ?
grad + offset_y * grad_quadstep + (offset_x << 1) : grad;
__global const QANGLE_TYPE* qangle_ptr = (gid < blocks_total) ?
qangle + offset_y * qangle_step + (offset_x << 1) : qangle;
__local float* hist = hists + 12 * (cell_y * CELLS_PER_BLOCK_Y + cell_x) +
cell_thread_x;
for (int bin_id = 0; bin_id < cnbins; ++bin_id)
hist[bin_id * 48] = 0.f;
const int dist_x = -4 + cell_thread_x - 4 * cell_x;
const int dist_center_x = dist_x - 4 * (1 - 2 * cell_x);
const int dist_y_begin = -4 - 4 * lidY;
for (int dist_y = dist_y_begin; dist_y < dist_y_begin + 12; ++dist_y)
{
float2 vote = (float2) (grad_ptr[0], grad_ptr[1]);
QANGLE_TYPE2 bin = (QANGLE_TYPE2) (qangle_ptr[0], qangle_ptr[1]);
grad_ptr += grad_quadstep;
qangle_ptr += qangle_step;
int dist_center_y = dist_y - 4 * (1 - 2 * cell_y);
int idx = (dist_center_y + 8) * 16 + (dist_center_x + 8);
float gaussian = gauss_w_lut[idx];
idx = (dist_y + 8) * 16 + (dist_x + 8);
float interp_weight = gauss_w_lut[256+idx];
hist[bin.x * 48] += gaussian * interp_weight * vote.x;
hist[bin.y * 48] += gaussian * interp_weight * vote.y;
}
barrier(CLK_LOCAL_MEM_FENCE);
volatile __local float* hist_ = hist;
for (int bin_id = 0; bin_id < cnbins; ++bin_id, hist_ += 48)
{
if (cell_thread_x < 6)
hist_[0] += hist_[6];
barrier(CLK_LOCAL_MEM_FENCE);
if (cell_thread_x < 3)
hist_[0] += hist_[3];
barrier(CLK_LOCAL_MEM_FENCE);
if (cell_thread_x == 0)
final_hist[(cell_x * 2 + cell_y) * cnbins + bin_id] =
hist_[0] + hist_[1] + hist_[2];
}
barrier(CLK_LOCAL_MEM_FENCE);
int tid = (cell_y * CELLS_PER_BLOCK_Y + cell_x) * 12 + cell_thread_x;
if ((tid < cblock_hist_size) && (gid < blocks_total))
{
__global float* block_hist = block_hists +
(gidY * img_block_width + gidX) * cblock_hist_size;
block_hist[tid] = final_hist[tid];
}
}
//-------------------------------------------------------------
// Normalization of histograms via L2Hys_norm
// optimized for the case of 9 bins
__kernel void normalize_hists_36_kernel(__global float* block_hists,
const float threshold, __local float *squares)
{
const int tid = get_local_id(0);
const int gid = get_global_id(0);
const int bid = tid / 36; /* block-hist id, (0 - 6) */
const int boffset = bid * 36; /* block-hist offset in the work-group */
const int hid = tid - boffset; /* histogram bin id, (0 - 35) */
float elem = block_hists[gid];
squares[tid] = elem * elem;
barrier(CLK_LOCAL_MEM_FENCE);
__local float* smem = squares + boffset;
float sum = smem[hid];
if (hid < 18)
smem[hid] = sum = sum + smem[hid + 18];
barrier(CLK_LOCAL_MEM_FENCE);
if (hid < 9)
smem[hid] = sum = sum + smem[hid + 9];
barrier(CLK_LOCAL_MEM_FENCE);
if (hid < 4)
smem[hid] = sum + smem[hid + 4];
barrier(CLK_LOCAL_MEM_FENCE);
sum = smem[0] + smem[1] + smem[2] + smem[3] + smem[8];
elem = elem / (sqrt(sum) + 3.6f);
elem = min(elem, threshold);
barrier(CLK_LOCAL_MEM_FENCE);
squares[tid] = elem * elem;
barrier(CLK_LOCAL_MEM_FENCE);
sum = smem[hid];
if (hid < 18)
smem[hid] = sum = sum + smem[hid + 18];
barrier(CLK_LOCAL_MEM_FENCE);
if (hid < 9)
smem[hid] = sum = sum + smem[hid + 9];
barrier(CLK_LOCAL_MEM_FENCE);
if (hid < 4)
smem[hid] = sum + smem[hid + 4];
barrier(CLK_LOCAL_MEM_FENCE);
sum = smem[0] + smem[1] + smem[2] + smem[3] + smem[8];
block_hists[gid] = elem / (sqrt(sum) + 1e-3f);
}
//-------------------------------------------------------------
// Normalization of histograms via L2Hys_norm
//
inline float reduce_smem(volatile __local float* smem, int size)
{
unsigned int tid = get_local_id(0);
float sum = smem[tid];
if (size >= 512) { if (tid < 256) smem[tid] = sum = sum + smem[tid + 256];
barrier(CLK_LOCAL_MEM_FENCE); }
if (size >= 256) { if (tid < 128) smem[tid] = sum = sum + smem[tid + 128];
barrier(CLK_LOCAL_MEM_FENCE); }
if (size >= 128) { if (tid < 64) smem[tid] = sum = sum + smem[tid + 64];
barrier(CLK_LOCAL_MEM_FENCE); }
if (size >= 64) { if (tid < 32) smem[tid] = sum = sum + smem[tid + 32];
barrier(CLK_LOCAL_MEM_FENCE); }
if (size >= 32) { if (tid < 16) smem[tid] = sum = sum + smem[tid + 16];
barrier(CLK_LOCAL_MEM_FENCE); }
if (size >= 16) { if (tid < 8) smem[tid] = sum = sum + smem[tid + 8];
barrier(CLK_LOCAL_MEM_FENCE); }
if (size >= 8) { if (tid < 4) smem[tid] = sum = sum + smem[tid + 4];
barrier(CLK_LOCAL_MEM_FENCE); }
if (size >= 4) { if (tid < 2) smem[tid] = sum = sum + smem[tid + 2];
barrier(CLK_LOCAL_MEM_FENCE); }
if (size >= 2) { if (tid < 1) smem[tid] = sum = sum + smem[tid + 1];
barrier(CLK_LOCAL_MEM_FENCE); }
return sum;
}
__kernel void normalize_hists_kernel(
const int nthreads, const int block_hist_size, const int img_block_width,
__global float* block_hists, const float threshold, __local float *squares)
{
const int tid = get_local_id(0);
const int gidX = get_group_id(0);
const int gidY = get_group_id(1);
__global float* hist = block_hists + (gidY * img_block_width + gidX) *
block_hist_size + tid;
float elem = 0.f;
if (tid < block_hist_size)
elem = hist[0];
squares[tid] = elem * elem;
barrier(CLK_LOCAL_MEM_FENCE);
float sum = reduce_smem(squares, nthreads);
float scale = 1.0f / (sqrt(sum) + 0.1f * block_hist_size);
elem = min(elem * scale, threshold);
barrier(CLK_LOCAL_MEM_FENCE);
squares[tid] = elem * elem;
barrier(CLK_LOCAL_MEM_FENCE);
sum = reduce_smem(squares, nthreads);
scale = 1.0f / (sqrt(sum) + 1e-3f);
if (tid < block_hist_size)
hist[0] = elem * scale;
}
#define reduce_with_sync(target, sharedMemory, localMemory, tid, offset) \
if (tid < target) sharedMemory[tid] = localMemory = localMemory + sharedMemory[tid + offset]; \
barrier(CLK_LOCAL_MEM_FENCE);
//---------------------------------------------------------------------
// Linear SVM based classification
// 48x96 window, 9 bins and default parameters
// 180 threads, each thread corresponds to a bin in a row
__kernel void classify_hists_180_kernel(
const int cdescr_width, const int cdescr_height, const int cblock_hist_size,
const int img_win_width, const int img_block_width,
const int win_block_stride_x, const int win_block_stride_y,
__global const float * block_hists, __global const float* coefs,
float free_coef, float threshold, __global uchar* labels)
{
const int tid = get_local_id(0);
const int gidX = get_group_id(0);
const int gidY = get_group_id(1);
__global const float* hist = block_hists + (gidY * win_block_stride_y *
img_block_width + gidX * win_block_stride_x) * cblock_hist_size;
float product = 0.f;
for (int i = 0; i < cdescr_height; i++)
{
product += coefs[i * cdescr_width + tid] *
hist[i * img_block_width * cblock_hist_size + tid];
}
__local float products[180];
products[tid] = product;
barrier(CLK_LOCAL_MEM_FENCE);
reduce_with_sync(90, products, product, tid, 90);
reduce_with_sync(45, products, product, tid, 45);
reduce_with_sync(13, products, product, tid, 32); // 13 is not typo
reduce_with_sync(16, products, product, tid, 16);
reduce_with_sync(8, products, product, tid, 8);
reduce_with_sync(4, products, product, tid, 4);
reduce_with_sync(2, products, product, tid, 2);
if (tid == 0){
product = product + products[tid + 1];
labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold);
}
}
//---------------------------------------------------------------------
// Linear SVM based classification
// 64x128 window, 9 bins and default parameters
// 256 threads, 252 of them are used
__kernel void classify_hists_252_kernel(
const int cdescr_width, const int cdescr_height, const int cblock_hist_size,
const int img_win_width, const int img_block_width,
const int win_block_stride_x, const int win_block_stride_y,
__global const float * block_hists, __global const float* coefs,
float free_coef, float threshold, __global uchar* labels)
{
const int tid = get_local_id(0);
const int gidX = get_group_id(0);
const int gidY = get_group_id(1);
__global const float* hist = block_hists + (gidY * win_block_stride_y *
img_block_width + gidX * win_block_stride_x) * cblock_hist_size;
float product = 0.f;
if (tid < cdescr_width)
{
for (int i = 0; i < cdescr_height; i++)
product += coefs[i * cdescr_width + tid] *
hist[i * img_block_width * cblock_hist_size + tid];
}
__local float products[NTHREADS];
products[tid] = product;
barrier(CLK_LOCAL_MEM_FENCE);
reduce_with_sync(128, products, product, tid, 128);
reduce_with_sync(64, products, product, tid, 64);
reduce_with_sync(32, products, product, tid, 32);
reduce_with_sync(16, products, product, tid, 16);
reduce_with_sync(8, products, product, tid, 8);
reduce_with_sync(4, products, product, tid, 4);
reduce_with_sync(2, products, product, tid, 2);
if (tid == 0){
product = product + products[tid + 1];
labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold);
}
}
//---------------------------------------------------------------------
// Linear SVM based classification
// 256 threads
__kernel void classify_hists_kernel(
const int cdescr_size, const int cdescr_width, const int cblock_hist_size,
const int img_win_width, const int img_block_width,
const int win_block_stride_x, const int win_block_stride_y,
__global const float * block_hists, __global const float* coefs,
float free_coef, float threshold, __global uchar* labels)
{
const int tid = get_local_id(0);
const int gidX = get_group_id(0);
const int gidY = get_group_id(1);
__global const float* hist = block_hists + (gidY * win_block_stride_y *
img_block_width + gidX * win_block_stride_x) * cblock_hist_size;
float product = 0.f;
for (int i = tid; i < cdescr_size; i += NTHREADS)
{
int offset_y = i / cdescr_width;
int offset_x = i - offset_y * cdescr_width;
product += coefs[i] *
hist[offset_y * img_block_width * cblock_hist_size + offset_x];
}
__local float products[NTHREADS];
products[tid] = product;
barrier(CLK_LOCAL_MEM_FENCE);
reduce_with_sync(128, products, product, tid, 128);
reduce_with_sync(64, products, product, tid, 64);
reduce_with_sync(32, products, product, tid, 32);
reduce_with_sync(16, products, product, tid, 16);
reduce_with_sync(8, products, product, tid, 8);
reduce_with_sync(4, products, product, tid, 4);
reduce_with_sync(2, products, product, tid, 2);
if (tid == 0){
products[tid] = product = product + products[tid + 1];
labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold);
}
}
//----------------------------------------------------------------------------
// Extract descriptors
__kernel void extract_descrs_by_rows_kernel(
const int cblock_hist_size, const int descriptors_quadstep,
const int cdescr_size, const int cdescr_width, const int img_block_width,
const int win_block_stride_x, const int win_block_stride_y,
__global const float* block_hists, __global float* descriptors)
{
int tid = get_local_id(0);
int gidX = get_group_id(0);
int gidY = get_group_id(1);
// Get left top corner of the window in src
__global const float* hist = block_hists + (gidY * win_block_stride_y *
img_block_width + gidX * win_block_stride_x) * cblock_hist_size;
// Get left top corner of the window in dst
__global float* descriptor = descriptors +
(gidY * get_num_groups(0) + gidX) * descriptors_quadstep;
// Copy elements from src to dst
for (int i = tid; i < cdescr_size; i += NTHREADS)
{
int offset_y = i / cdescr_width;
int offset_x = i - offset_y * cdescr_width;
descriptor[i] = hist[offset_y * img_block_width * cblock_hist_size + offset_x];
}
}
__kernel void extract_descrs_by_cols_kernel(
const int cblock_hist_size, const int descriptors_quadstep, const int cdescr_size,
const int cnblocks_win_x, const int cnblocks_win_y, const int img_block_width,
const int win_block_stride_x, const int win_block_stride_y,
__global const float* block_hists, __global float* descriptors)
{
int tid = get_local_id(0);
int gidX = get_group_id(0);
int gidY = get_group_id(1);
// Get left top corner of the window in src
__global const float* hist = block_hists + (gidY * win_block_stride_y *
img_block_width + gidX * win_block_stride_x) * cblock_hist_size;
// Get left top corner of the window in dst
__global float* descriptor = descriptors +
(gidY * get_num_groups(0) + gidX) * descriptors_quadstep;
// Copy elements from src to dst
for (int i = tid; i < cdescr_size; i += NTHREADS)
{
int block_idx = i / cblock_hist_size;
int idx_in_block = i - block_idx * cblock_hist_size;
int y = block_idx / cnblocks_win_x;
int x = block_idx - y * cnblocks_win_x;
descriptor[(x * cnblocks_win_y + y) * cblock_hist_size + idx_in_block] =
hist[(y * img_block_width + x) * cblock_hist_size + idx_in_block];
}
}
//----------------------------------------------------------------------------
// Gradients computation
__kernel void compute_gradients_8UC4_kernel(
const int height, const int width,
const int img_step, const int grad_quadstep, const int qangle_step,
const __global uchar4 * img, __global float * grad, __global QANGLE_TYPE * qangle,
const float angle_scale, const char correct_gamma, const int cnbins)
{
const int x = get_global_id(0);
const int tid = get_local_id(0);
const int gSizeX = get_local_size(0);
const int gidY = get_group_id(1);
__global const uchar4* row = img + gidY * img_step;
__local float sh_row[(NTHREADS + 2) * 3];
uchar4 val;
if (x < width)
val = row[x];
else
val = row[width - 2];
sh_row[tid + 1] = val.x;
sh_row[tid + 1 + (NTHREADS + 2)] = val.y;
sh_row[tid + 1 + 2 * (NTHREADS + 2)] = val.z;
if (tid == 0)
{
val = row[max(x - 1, 1)];
sh_row[0] = val.x;
sh_row[(NTHREADS + 2)] = val.y;
sh_row[2 * (NTHREADS + 2)] = val.z;
}
if (tid == gSizeX - 1)
{
val = row[min(x + 1, width - 2)];
sh_row[gSizeX + 1] = val.x;
sh_row[gSizeX + 1 + (NTHREADS + 2)] = val.y;
sh_row[gSizeX + 1 + 2 * (NTHREADS + 2)] = val.z;
}
barrier(CLK_LOCAL_MEM_FENCE);
if (x < width)
{
float4 a = (float4) (sh_row[tid], sh_row[tid + (NTHREADS + 2)],
sh_row[tid + 2 * (NTHREADS + 2)], 0);
float4 b = (float4) (sh_row[tid + 2], sh_row[tid + 2 + (NTHREADS + 2)],
sh_row[tid + 2 + 2 * (NTHREADS + 2)], 0);
float4 dx;
if (correct_gamma == 1)
dx = sqrt(b) - sqrt(a);
else
dx = b - a;
float4 dy = (float4) 0.f;
if (gidY > 0 && gidY < height - 1)
{
a = convert_float4(img[(gidY - 1) * img_step + x].xyzw);
b = convert_float4(img[(gidY + 1) * img_step + x].xyzw);
if (correct_gamma == 1)
dy = sqrt(b) - sqrt(a);
else
dy = b - a;
}
float4 mag = hypot(dx, dy);
float best_dx = dx.x;
float best_dy = dy.x;
float mag0 = mag.x;
if (mag0 < mag.y)
{
best_dx = dx.y;
best_dy = dy.y;
mag0 = mag.y;
}
if (mag0 < mag.z)
{
best_dx = dx.z;
best_dy = dy.z;
mag0 = mag.z;
}
float ang = (atan2(best_dy, best_dx) + CV_PI_F) * angle_scale - 0.5f;
int hidx = (int)floor(ang);
ang -= hidx;
hidx = (hidx + cnbins) % cnbins;
qangle[(gidY * qangle_step + x) << 1] = hidx;
qangle[((gidY * qangle_step + x) << 1) + 1] = (hidx + 1) % cnbins;
grad[(gidY * grad_quadstep + x) << 1] = mag0 * (1.f - ang);
grad[((gidY * grad_quadstep + x) << 1) + 1] = mag0 * ang;
}
}
__kernel void compute_gradients_8UC1_kernel(
const int height, const int width,
const int img_step, const int grad_quadstep, const int qangle_step,
__global const uchar * img, __global float * grad, __global QANGLE_TYPE * qangle,
const float angle_scale, const char correct_gamma, const int cnbins)
{
const int x = get_global_id(0);
const int tid = get_local_id(0);
const int gSizeX = get_local_size(0);
const int gidY = get_group_id(1);
__global const uchar* row = img + gidY * img_step;
__local float sh_row[NTHREADS + 2];
if (x < width)
sh_row[tid + 1] = row[x];
else
sh_row[tid + 1] = row[width - 2];
if (tid == 0)
sh_row[0] = row[max(x - 1, 1)];
if (tid == gSizeX - 1)
sh_row[gSizeX + 1] = row[min(x + 1, width - 2)];
barrier(CLK_LOCAL_MEM_FENCE);
if (x < width)
{
float dx;
if (correct_gamma == 1)
dx = sqrt(sh_row[tid + 2]) - sqrt(sh_row[tid]);
else
dx = sh_row[tid + 2] - sh_row[tid];
float dy = 0.f;
if (gidY > 0 && gidY < height - 1)
{
float a = (float) img[ (gidY + 1) * img_step + x ];
float b = (float) img[ (gidY - 1) * img_step + x ];
if (correct_gamma == 1)
dy = sqrt(a) - sqrt(b);
else
dy = a - b;
}
float mag = hypot(dx, dy);
float ang = (atan2(dy, dx) + CV_PI_F) * angle_scale - 0.5f;
int hidx = (int)floor(ang);
ang -= hidx;
hidx = (hidx + cnbins) % cnbins;
qangle[ (gidY * qangle_step + x) << 1 ] = hidx;
qangle[ ((gidY * qangle_step + x) << 1) + 1 ] = (hidx + 1) % cnbins;
grad[ (gidY * grad_quadstep + x) << 1 ] = mag * (1.f - ang);
grad[ ((gidY * grad_quadstep + x) << 1) + 1 ] = mag * ang;
}
}

View File

@ -1,140 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Niko Li, newlife20080214@gmail.com
// Jia Haipeng, jiahaipeng95@gmail.com
// Shengen Yan, yanshengen@gmail.com
// Jiang Liyuan,jlyuan001.good@163.com
// Rock Li, Rock.Li@amd.com
// Zailong Wu, bullet@yeah.net
// Yao Wang, bitwangyaoyao@gmail.com
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "../test_precomp.hpp"
#include "opencv2/ts/ocl_test.hpp"
#ifdef HAVE_OPENCL
namespace opencv_test {
namespace ocl {
///////////////////// HOG /////////////////////////////
PARAM_TEST_CASE(HOG, Size, MatType)
{
Size winSize;
int type;
Mat img;
UMat uimg;
virtual void SetUp()
{
winSize = GET_PARAM(0);
type = GET_PARAM(1);
img = readImage("cascadeandhog/images/image_00000000_0.png", IMREAD_GRAYSCALE);
ASSERT_FALSE(img.empty());
img.copyTo(uimg);
}
};
OCL_TEST_P(HOG, GetDescriptors)
{
HOGDescriptor hog;
hog.gammaCorrection = true;
hog.setSVMDetector(hog.getDefaultPeopleDetector());
std::vector<float> cpu_descriptors;
std::vector<float> gpu_descriptors;
OCL_OFF(hog.compute(img, cpu_descriptors, hog.winSize));
OCL_ON(hog.compute(uimg, gpu_descriptors, hog.winSize));
Mat cpu_desc(cpu_descriptors), gpu_desc(gpu_descriptors);
EXPECT_MAT_SIMILAR(cpu_desc, gpu_desc, 1e-1);
}
OCL_TEST_P(HOG, SVMDetector)
{
HOGDescriptor hog_first, hog_second;
// empty -> empty
hog_first.copyTo(hog_second);
// first -> both
hog_first.setSVMDetector(hog_first.getDefaultPeopleDetector());
hog_first.copyTo(hog_second);
// both -> both
hog_first.copyTo(hog_second);
// second -> empty
hog_first.setSVMDetector(cv::noArray());
hog_first.copyTo(hog_second);
}
OCL_TEST_P(HOG, Detect)
{
HOGDescriptor hog;
hog.winSize = winSize;
hog.gammaCorrection = true;
if (winSize.width == 48 && winSize.height == 96)
hog.setSVMDetector(hog.getDaimlerPeopleDetector());
else
hog.setSVMDetector(hog.getDefaultPeopleDetector());
std::vector<Rect> cpu_found;
std::vector<Rect> gpu_found;
OCL_OFF(hog.detectMultiScale(img, cpu_found, 0, Size(8, 8), Size(0, 0), 1.05, 6));
OCL_ON(hog.detectMultiScale(uimg, gpu_found, 0, Size(8, 8), Size(0, 0), 1.05, 6));
EXPECT_LT(checkRectSimilarity(img.size(), cpu_found, gpu_found), 0.05);
}
INSTANTIATE_TEST_CASE_P(OCL_ObjDetect, HOG, testing::Combine(
testing::Values(Size(64, 128), Size(48, 96)),
testing::Values( MatType(CV_8UC1) ) ) );
}} // namespace
#endif

File diff suppressed because it is too large Load Diff

View File

@ -109,11 +109,9 @@ imgproc = {
],
}
objdetect = {'': ['groupRectangles', 'getPredefinedDictionary', 'extendDictionary',
objdetect = {'': ['getPredefinedDictionary', 'extendDictionary',
'drawDetectedMarkers', 'generateImageMarker', 'drawDetectedCornersCharuco',
'drawDetectedDiamonds'],
'HOGDescriptor': ['load', 'HOGDescriptor', 'getDefaultPeopleDetector', 'getDaimlerPeopleDetector', 'setSVMDetector', 'detectMultiScale'],
'CascadeClassifier': ['load', 'detectMultiScale2', 'CascadeClassifier', 'detectMultiScale3', 'empty', 'detectMultiScale'],
'GraphicalCodeDetector': ['decode', 'detect', 'detectAndDecode', 'detectMulti', 'decodeMulti', 'detectAndDecodeMulti'],
'QRCodeDetector': ['QRCodeDetector', 'decode', 'detect', 'detectAndDecode', 'detectMulti', 'decodeMulti', 'detectAndDecodeMulti', 'decodeCurved', 'detectAndDecodeCurved', 'setEpsX', 'setEpsY'],
'aruco_PredefinedDictionaryType': [],

View File

@ -1,111 +0,0 @@
#if defined(__linux__) || defined(LINUX) || defined(__APPLE__) || defined(ANDROID) || (defined(_MSC_VER) && _MSC_VER>=1800)
#include <opencv2/imgproc.hpp> // Gaussian Blur
#include <opencv2/core.hpp> // Basic OpenCV structures (cv::Mat, Scalar)
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp> // OpenCV window I/O
#include <opencv2/features2d.hpp>
#include <opencv2/objdetect.hpp>
#include <stdio.h>
using namespace std;
using namespace cv;
const string WindowName = "Face Detection example";
class CascadeDetectorAdapter: public DetectionBasedTracker::IDetector
{
public:
CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector):
IDetector(),
Detector(detector)
{
CV_Assert(detector);
}
void detect(const cv::Mat &Image, std::vector<cv::Rect> &objects) CV_OVERRIDE
{
Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours, 0, minObjSize, maxObjSize);
}
virtual ~CascadeDetectorAdapter() CV_OVERRIDE
{}
private:
CascadeDetectorAdapter();
cv::Ptr<cv::CascadeClassifier> Detector;
};
int main(int , char** )
{
namedWindow(WindowName);
VideoCapture VideoStream(0);
if (!VideoStream.isOpened())
{
printf("Error: Cannot open video stream from camera\n");
return 1;
}
std::string cascadeFrontalfilename = samples::findFile("data/lbpcascades/lbpcascade_frontalface.xml");
cv::Ptr<cv::CascadeClassifier> cascade = makePtr<cv::CascadeClassifier>(cascadeFrontalfilename);
cv::Ptr<DetectionBasedTracker::IDetector> MainDetector = makePtr<CascadeDetectorAdapter>(cascade);
if ( cascade->empty() )
{
printf("Error: Cannot load %s\n", cascadeFrontalfilename.c_str());
return 2;
}
cascade = makePtr<cv::CascadeClassifier>(cascadeFrontalfilename);
cv::Ptr<DetectionBasedTracker::IDetector> TrackingDetector = makePtr<CascadeDetectorAdapter>(cascade);
if ( cascade->empty() )
{
printf("Error: Cannot load %s\n", cascadeFrontalfilename.c_str());
return 2;
}
DetectionBasedTracker::Parameters params;
DetectionBasedTracker Detector(MainDetector, TrackingDetector, params);
if (!Detector.run())
{
printf("Error: Detector initialization failed\n");
return 2;
}
Mat ReferenceFrame;
Mat GrayFrame;
vector<Rect> Faces;
do
{
VideoStream >> ReferenceFrame;
cvtColor(ReferenceFrame, GrayFrame, COLOR_BGR2GRAY);
Detector.process(GrayFrame);
Detector.getObjects(Faces);
for (size_t i = 0; i < Faces.size(); i++)
{
rectangle(ReferenceFrame, Faces[i], Scalar(0,255,0));
}
imshow(WindowName, ReferenceFrame);
} while (waitKey(30) < 0);
Detector.stop();
return 0;
}
#else
#include <stdio.h>
int main()
{
printf("This sample works for UNIX or ANDROID or Visual Studio 2013+ only\n");
return 0;
}
#endif

View File

@ -1,257 +0,0 @@
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
using namespace std;
using namespace cv;
static void help(const char** argv)
{
cout << "\nThis program demonstrates the use of cv::CascadeClassifier class to detect objects (Face + eyes). You can use Haar or LBP features.\n"
"This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n"
"It's most known use is for faces.\n"
"Usage:\n"
<< argv[0]
<< " [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n"
" [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n"
" [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n"
" [--try-flip]\n"
" [filename|camera_index]\n\n"
"example:\n"
<< argv[0]
<< " --cascade=\"data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"data/haarcascades/haarcascade_eye_tree_eyeglasses.xml\" --scale=1.3\n\n"
"During execution:\n\tHit any key to quit.\n"
"\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
}
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip );
string cascadeName;
string nestedCascadeName;
int main( int argc, const char** argv )
{
VideoCapture capture;
Mat frame, image;
string inputName;
bool tryflip;
CascadeClassifier cascade, nestedCascade;
double scale;
cv::CommandLineParser parser(argc, argv,
"{help h||}"
"{cascade|data/haarcascades/haarcascade_frontalface_alt.xml|}"
"{nested-cascade|data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|}"
"{scale|1|}{try-flip||}{@filename||}"
);
if (parser.has("help"))
{
help(argv);
return 0;
}
cascadeName = parser.get<string>("cascade");
nestedCascadeName = parser.get<string>("nested-cascade");
scale = parser.get<double>("scale");
if (scale < 1)
scale = 1;
tryflip = parser.has("try-flip");
inputName = parser.get<string>("@filename");
if (!parser.check())
{
parser.printErrors();
return 0;
}
if (!nestedCascade.load(samples::findFileOrKeep(nestedCascadeName)))
cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
if (!cascade.load(samples::findFile(cascadeName)))
{
cerr << "ERROR: Could not load classifier cascade" << endl;
help(argv);
return -1;
}
if( inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1) )
{
int camera = inputName.empty() ? 0 : inputName[0] - '0';
if(!capture.open(camera))
{
cout << "Capture from camera #" << camera << " didn't work" << endl;
return 1;
}
}
else if (!inputName.empty())
{
image = imread(samples::findFileOrKeep(inputName), IMREAD_COLOR);
if (image.empty())
{
if (!capture.open(samples::findFileOrKeep(inputName)))
{
cout << "Could not read " << inputName << endl;
return 1;
}
}
}
else
{
image = imread(samples::findFile("lena.jpg"), IMREAD_COLOR);
if (image.empty())
{
cout << "Couldn't read lena.jpg" << endl;
return 1;
}
}
if( capture.isOpened() )
{
cout << "Video capturing has been started ..." << endl;
for(;;)
{
capture >> frame;
if( frame.empty() )
break;
Mat frame1 = frame.clone();
detectAndDraw( frame1, cascade, nestedCascade, scale, tryflip );
char c = (char)waitKey(10);
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
}
else
{
cout << "Detecting face(s) in " << inputName << endl;
if( !image.empty() )
{
detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
waitKey(0);
}
else if( !inputName.empty() )
{
/* assume it is a text file containing the
list of the image filenames to be processed - one per line */
FILE* f = fopen( inputName.c_str(), "rt" );
if( f )
{
char buf[1000+1];
while( fgets( buf, 1000, f ) )
{
int len = (int)strlen(buf);
while( len > 0 && isspace(buf[len-1]) )
len--;
buf[len] = '\0';
cout << "file " << buf << endl;
image = imread( buf, IMREAD_COLOR );
if( !image.empty() )
{
detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
char c = (char)waitKey(0);
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
else
{
cerr << "Aw snap, couldn't read image " << buf << endl;
}
}
fclose(f);
}
}
}
return 0;
}
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip )
{
double t = 0;
vector<Rect> faces, faces2;
const static Scalar colors[] =
{
Scalar(255,0,0),
Scalar(255,128,0),
Scalar(255,255,0),
Scalar(0,255,0),
Scalar(0,128,255),
Scalar(0,255,255),
Scalar(0,0,255),
Scalar(255,0,255)
};
Mat gray, smallImg;
cvtColor( img, gray, COLOR_BGR2GRAY );
double fx = 1 / scale;
resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT );
equalizeHist( smallImg, smallImg );
t = (double)getTickCount();
cascade.detectMultiScale( smallImg, faces,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
if( tryflip )
{
flip(smallImg, smallImg, 1);
cascade.detectMultiScale( smallImg, faces2,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r )
{
faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
}
}
t = (double)getTickCount() - t;
printf( "detection time = %g ms\n", t*1000/getTickFrequency());
for ( size_t i = 0; i < faces.size(); i++ )
{
Rect r = faces[i];
Mat smallImgROI;
vector<Rect> nestedObjects;
Point center;
Scalar color = colors[i%8];
int radius;
double aspect_ratio = (double)r.width/r.height;
if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
{
center.x = cvRound((r.x + r.width*0.5)*scale);
center.y = cvRound((r.y + r.height*0.5)*scale);
radius = cvRound((r.width + r.height)*0.25*scale);
circle( img, center, radius, color, 3, 8, 0 );
}
else
rectangle( img, Point(cvRound(r.x*scale), cvRound(r.y*scale)),
Point(cvRound((r.x + r.width-1)*scale), cvRound((r.y + r.height-1)*scale)),
color, 3, 8, 0);
if( nestedCascade.empty() )
continue;
smallImgROI = smallImg( r );
nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
//|CASCADE_DO_CANNY_PRUNING
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
for ( size_t j = 0; j < nestedObjects.size(); j++ )
{
Rect nr = nestedObjects[j];
center.x = cvRound((r.x + nr.x + nr.width*0.5)*scale);
center.y = cvRound((r.y + nr.y + nr.height*0.5)*scale);
radius = cvRound((nr.width + nr.height)*0.25*scale);
circle( img, center, radius, color, 3, 8, 0 );
}
}
imshow( "result", img );
}

View File

@ -1,215 +0,0 @@
/*
* Author: Samyak Datta (datta[dot]samyak[at]gmail.com)
*
* A program to detect facial feature points using
* Haarcascade classifiers for face, eyes, nose and mouth
*
*/
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
using namespace cv;
// Functions for facial feature detection
static void help(char** argv);
static void detectFaces(Mat&, vector<Rect_<int> >&, string);
static void detectEyes(Mat&, vector<Rect_<int> >&, string);
static void detectNose(Mat&, vector<Rect_<int> >&, string);
static void detectMouth(Mat&, vector<Rect_<int> >&, string);
static void detectFacialFeaures(Mat&, const vector<Rect_<int> >, string, string, string);
string input_image_path;
string face_cascade_path, eye_cascade_path, nose_cascade_path, mouth_cascade_path;
int main(int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv,
"{eyes||}{nose||}{mouth||}{help h||}{@image||}{@facexml||}");
if (parser.has("help"))
{
help(argv);
return 0;
}
input_image_path = parser.get<string>("@image");
face_cascade_path = parser.get<string>("@facexml");
eye_cascade_path = parser.has("eyes") ? parser.get<string>("eyes") : "";
nose_cascade_path = parser.has("nose") ? parser.get<string>("nose") : "";
mouth_cascade_path = parser.has("mouth") ? parser.get<string>("mouth") : "";
if (input_image_path.empty() || face_cascade_path.empty())
{
cout << "IMAGE or FACE_CASCADE are not specified";
return 1;
}
// Load image and cascade classifier files
Mat image;
image = imread(samples::findFile(input_image_path));
// Detect faces and facial features
vector<Rect_<int> > faces;
detectFaces(image, faces, face_cascade_path);
detectFacialFeaures(image, faces, eye_cascade_path, nose_cascade_path, mouth_cascade_path);
imshow("Result", image);
waitKey(0);
return 0;
}
static void help(char** argv)
{
cout << "\nThis file demonstrates facial feature points detection using Haarcascade classifiers.\n"
"The program detects a face and eyes, nose and mouth inside the face."
"The code has been tested on the Japanese Female Facial Expression (JAFFE) database and found"
"to give reasonably accurate results. \n";
cout << "\nUSAGE: " << argv[0] << " [IMAGE] [FACE_CASCADE] [OPTIONS]\n"
"IMAGE\n\tPath to the image of a face taken as input.\n"
"FACE_CASCSDE\n\t Path to a haarcascade classifier for face detection.\n"
"OPTIONS: \nThere are 3 options available which are described in detail. There must be a "
"space between the option and it's argument (All three options accept arguments).\n"
"\t-eyes=<eyes_cascade> : Specify the haarcascade classifier for eye detection.\n"
"\t-nose=<nose_cascade> : Specify the haarcascade classifier for nose detection.\n"
"\t-mouth=<mouth-cascade> : Specify the haarcascade classifier for mouth detection.\n";
cout << "EXAMPLE:\n"
"(1) " << argv[0] << " image.jpg face.xml -eyes=eyes.xml -mouth=mouth.xml\n"
"\tThis will detect the face, eyes and mouth in image.jpg.\n"
"(2) " << argv[0] << " image.jpg face.xml -nose=nose.xml\n"
"\tThis will detect the face and nose in image.jpg.\n"
"(3) " << argv[0] << " image.jpg face.xml\n"
"\tThis will detect only the face in image.jpg.\n";
cout << " \n\nThe classifiers for face and eyes can be downloaded from : "
" \nhttps://github.com/opencv/opencv/tree/5.x/data/haarcascades";
cout << "\n\nThe classifiers for nose and mouth can be downloaded from : "
" \nhttps://github.com/opencv/opencv_contrib/tree/5.x/modules/face/data/cascades\n";
}
static void detectFaces(Mat& img, vector<Rect_<int> >& faces, string cascade_path)
{
CascadeClassifier face_cascade;
face_cascade.load(samples::findFile(cascade_path));
if (!face_cascade.empty())
face_cascade.detectMultiScale(img, faces, 1.15, 3, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}
static void detectFacialFeaures(Mat& img, const vector<Rect_<int> > faces, string eye_cascade,
string nose_cascade, string mouth_cascade)
{
for(unsigned int i = 0; i < faces.size(); ++i)
{
// Mark the bounding box enclosing the face
Rect face = faces[i];
rectangle(img, Point(face.x, face.y), Point(face.x+face.width, face.y+face.height),
Scalar(255, 0, 0), 1, 4);
// Eyes, nose and mouth will be detected inside the face (region of interest)
Mat ROI = img(Rect(face.x, face.y, face.width, face.height));
// Check if all features (eyes, nose and mouth) are being detected
bool is_full_detection = false;
if( (!eye_cascade.empty()) && (!nose_cascade.empty()) && (!mouth_cascade.empty()) )
is_full_detection = true;
// Detect eyes if classifier provided by the user
if(!eye_cascade.empty())
{
vector<Rect_<int> > eyes;
detectEyes(ROI, eyes, eye_cascade);
// Mark points corresponding to the centre of the eyes
for(unsigned int j = 0; j < eyes.size(); ++j)
{
Rect e = eyes[j];
circle(ROI, Point(e.x+e.width/2, e.y+e.height/2), 3, Scalar(0, 255, 0), -1, 8);
/* rectangle(ROI, Point(e.x, e.y), Point(e.x+e.width, e.y+e.height),
Scalar(0, 255, 0), 1, 4); */
}
}
// Detect nose if classifier provided by the user
double nose_center_height = 0.0;
if(!nose_cascade.empty())
{
vector<Rect_<int> > nose;
detectNose(ROI, nose, nose_cascade);
// Mark points corresponding to the centre (tip) of the nose
for(unsigned int j = 0; j < nose.size(); ++j)
{
Rect n = nose[j];
circle(ROI, Point(n.x+n.width/2, n.y+n.height/2), 3, Scalar(0, 255, 0), -1, 8);
nose_center_height = (n.y + n.height/2);
}
}
// Detect mouth if classifier provided by the user
double mouth_center_height = 0.0;
if(!mouth_cascade.empty())
{
vector<Rect_<int> > mouth;
detectMouth(ROI, mouth, mouth_cascade);
for(unsigned int j = 0; j < mouth.size(); ++j)
{
Rect m = mouth[j];
mouth_center_height = (m.y + m.height/2);
// The mouth should lie below the nose
if( (is_full_detection) && (mouth_center_height > nose_center_height) )
{
rectangle(ROI, Point(m.x, m.y), Point(m.x+m.width, m.y+m.height), Scalar(0, 255, 0), 1, 4);
}
else if( (is_full_detection) && (mouth_center_height <= nose_center_height) )
continue;
else
rectangle(ROI, Point(m.x, m.y), Point(m.x+m.width, m.y+m.height), Scalar(0, 255, 0), 1, 4);
}
}
}
return;
}
static void detectEyes(Mat& img, vector<Rect_<int> >& eyes, string cascade_path)
{
CascadeClassifier eyes_cascade;
eyes_cascade.load(samples::findFile(cascade_path, !cascade_path.empty()));
if (!eyes_cascade.empty())
eyes_cascade.detectMultiScale(img, eyes, 1.20, 5, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}
static void detectNose(Mat& img, vector<Rect_<int> >& nose, string cascade_path)
{
CascadeClassifier nose_cascade;
nose_cascade.load(samples::findFile(cascade_path, !cascade_path.empty()));
if (!nose_cascade.empty())
nose_cascade.detectMultiScale(img, nose, 1.20, 5, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}
static void detectMouth(Mat& img, vector<Rect_<int> >& mouth, string cascade_path)
{
CascadeClassifier mouth_cascade;
mouth_cascade.load(samples::findFile(cascade_path, !cascade_path.empty()));
if (!mouth_cascade.empty())
mouth_cascade.detectMultiScale(img, mouth, 1.20, 5, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}

View File

@ -1,129 +0,0 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include <opencv2/objdetect.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>
#include <iostream>
#include <iomanip>
using namespace cv;
using namespace std;
class Detector
{
enum Mode { Default, Daimler } m;
HOGDescriptor hog, hog_d;
public:
Detector() : m(Default), hog(), hog_d(Size(48, 96), Size(16, 16), Size(8, 8), Size(8, 8), 9)
{
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
hog_d.setSVMDetector(HOGDescriptor::getDaimlerPeopleDetector());
}
void toggleMode() { m = (m == Default ? Daimler : Default); }
string modeName() const { return (m == Default ? "Default" : "Daimler"); }
vector<Rect> detect(InputArray img)
{
// Run the detector with default parameters. to get a higher hit-rate
// (and more false alarms, respectively), decrease the hitThreshold and
// groupThreshold (set groupThreshold to 0 to turn off the grouping completely).
vector<Rect> found;
if (m == Default)
hog.detectMultiScale(img, found, 0, Size(8,8), Size(), 1.05, 2, false);
else if (m == Daimler)
hog_d.detectMultiScale(img, found, 0, Size(8,8), Size(), 1.05, 2, true);
return found;
}
void adjustRect(Rect & r) const
{
// The HOG detector returns slightly larger rectangles than the real objects,
// so we slightly shrink the rectangles to get a nicer output.
r.x += cvRound(r.width*0.1);
r.width = cvRound(r.width*0.8);
r.y += cvRound(r.height*0.07);
r.height = cvRound(r.height*0.8);
}
};
static const string keys = "{ help h | | print help message }"
"{ camera c | 0 | capture video from camera (device index starting from 0) }"
"{ video v | | use video as input }";
int main(int argc, char** argv)
{
CommandLineParser parser(argc, argv, keys);
parser.about("This sample demonstrates the use of the HoG descriptor.");
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
int camera = parser.get<int>("camera");
string file = parser.get<string>("video");
if (!parser.check())
{
parser.printErrors();
return 1;
}
VideoCapture cap;
if (file.empty())
cap.open(camera);
else
{
file = samples::findFileOrKeep(file);
cap.open(file);
}
if (!cap.isOpened())
{
cout << "Can not open video stream: '" << (file.empty() ? "<camera>" : file) << "'" << endl;
return 2;
}
cout << "Press 'q' or <ESC> to quit." << endl;
cout << "Press <space> to toggle between Default and Daimler detector" << endl;
Detector detector;
Mat frame;
for (;;)
{
cap >> frame;
if (frame.empty())
{
cout << "Finished reading: empty frame" << endl;
break;
}
int64 t = getTickCount();
vector<Rect> found = detector.detect(frame);
t = getTickCount() - t;
// show the window
{
ostringstream buf;
buf << "Mode: " << detector.modeName() << " ||| "
<< "FPS: " << fixed << setprecision(1) << (getTickFrequency() / (double)t);
putText(frame, buf.str(), Point(10, 30), FONT_HERSHEY_PLAIN, 2.0, Scalar(0, 0, 255), 2, LINE_AA);
}
for (vector<Rect>::iterator i = found.begin(); i != found.end(); ++i)
{
Rect &r = *i;
detector.adjustRect(r);
rectangle(frame, r.tl(), r.br(), cv::Scalar(0, 255, 0), 2);
}
imshow("People detector", frame);
// interact with user
const char key = (char)waitKey(1);
if (key == 27 || key == 'q') // ESC
{
cout << "Exit requested" << endl;
break;
}
else if (key == ' ')
{
detector.toggleMode();
}
}
return 0;
}

View File

@ -1,215 +0,0 @@
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
using namespace std;
using namespace cv;
static void help(const char** argv)
{
cout << "\nThis program demonstrates the smile detector.\n"
"Usage:\n" <<
argv[0] << " [--cascade=<cascade_path> this is the frontal face classifier]\n"
" [--smile-cascade=[<smile_cascade_path>]]\n"
" [--scale=<image scale greater or equal to 1, try 2.0 for example. The larger the faster the processing>]\n"
" [--try-flip]\n"
" [video_filename|camera_index]\n\n"
"Example:\n" <<
argv[0] << " --cascade=\"data/haarcascades/haarcascade_frontalface_alt.xml\" --smile-cascade=\"data/haarcascades/haarcascade_smile.xml\" --scale=2.0\n\n"
"During execution:\n\tHit any key to quit.\n"
"\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
}
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip );
string cascadeName;
string nestedCascadeName;
int main( int argc, const char** argv )
{
VideoCapture capture;
Mat frame, image;
string inputName;
bool tryflip;
help(argv);
CascadeClassifier cascade, nestedCascade;
double scale;
cv::CommandLineParser parser(argc, argv,
"{help h||}{scale|1|}"
"{cascade|data/haarcascades/haarcascade_frontalface_alt.xml|}"
"{smile-cascade|data/haarcascades/haarcascade_smile.xml|}"
"{try-flip||}{@input||}");
if (parser.has("help"))
{
help(argv);
return 0;
}
cascadeName = samples::findFile(parser.get<string>("cascade"));
nestedCascadeName = samples::findFile(parser.get<string>("smile-cascade"));
tryflip = parser.has("try-flip");
inputName = parser.get<string>("@input");
scale = parser.get<int>("scale");
if (!parser.check())
{
help(argv);
return 1;
}
if (scale < 1)
scale = 1;
if( !cascade.load( cascadeName ) )
{
cerr << "ERROR: Could not load face cascade" << endl;
help(argv);
return -1;
}
if( !nestedCascade.load( nestedCascadeName ) )
{
cerr << "ERROR: Could not load smile cascade" << endl;
help(argv);
return -1;
}
if( inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1) )
{
int c = inputName.empty() ? 0 : inputName[0] - '0' ;
if(!capture.open(c))
cout << "Capture from camera #" << c << " didn't work" << endl;
}
else if( inputName.size() )
{
inputName = samples::findFileOrKeep(inputName);
if(!capture.open( inputName ))
cout << "Could not read " << inputName << endl;
}
if( capture.isOpened() )
{
cout << "Video capturing has been started ..." << endl;
cout << endl << "NOTE: Smile intensity will only be valid after a first smile has been detected" << endl;
for(;;)
{
capture >> frame;
if( frame.empty() )
break;
Mat frame1 = frame.clone();
detectAndDraw( frame1, cascade, nestedCascade, scale, tryflip );
char c = (char)waitKey(10);
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
}
else
{
cerr << "ERROR: Could not initiate capture" << endl;
help(argv);
return -1;
}
return 0;
}
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip)
{
vector<Rect> faces, faces2;
const static Scalar colors[] =
{
Scalar(255,0,0),
Scalar(255,128,0),
Scalar(255,255,0),
Scalar(0,255,0),
Scalar(0,128,255),
Scalar(0,255,255),
Scalar(0,0,255),
Scalar(255,0,255)
};
Mat gray, smallImg;
cvtColor( img, gray, COLOR_BGR2GRAY );
double fx = 1 / scale;
resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT );
equalizeHist( smallImg, smallImg );
cascade.detectMultiScale( smallImg, faces,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
if( tryflip )
{
flip(smallImg, smallImg, 1);
cascade.detectMultiScale( smallImg, faces2,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r )
{
faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
}
}
for ( size_t i = 0; i < faces.size(); i++ )
{
Rect r = faces[i];
Mat smallImgROI;
vector<Rect> nestedObjects;
Point center;
Scalar color = colors[i%8];
int radius;
double aspect_ratio = (double)r.width/r.height;
if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
{
center.x = cvRound((r.x + r.width*0.5)*scale);
center.y = cvRound((r.y + r.height*0.5)*scale);
radius = cvRound((r.width + r.height)*0.25*scale);
circle( img, center, radius, color, 3, 8, 0 );
}
else
rectangle( img, Point(cvRound(r.x*scale), cvRound(r.y*scale)),
Point(cvRound((r.x + r.width-1)*scale), cvRound((r.y + r.height-1)*scale)),
color, 3, 8, 0);
const int half_height=cvRound((float)r.height/2);
r.y=r.y + half_height;
r.height = half_height-1;
smallImgROI = smallImg( r );
nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
1.1, 0, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
//|CASCADE_DO_CANNY_PRUNING
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
// The number of detected neighbors depends on image size (and also illumination, etc.). The
// following steps use a floating minimum and maximum of neighbors. Intensity thus estimated will be
//accurate only after a first smile has been displayed by the user.
const int smile_neighbors = (int)nestedObjects.size();
static int max_neighbors=-1;
static int min_neighbors=-1;
if (min_neighbors == -1) min_neighbors = smile_neighbors;
max_neighbors = MAX(max_neighbors, smile_neighbors);
// Draw rectangle on the left side of the image reflecting smile intensity
float intensityZeroOne = ((float)smile_neighbors - min_neighbors) / (max_neighbors - min_neighbors + 1);
int rect_height = cvRound((float)img.rows * intensityZeroOne);
Scalar col = Scalar((float)255 * intensityZeroOne, 0, 0);
rectangle(img, Point(0, img.rows), Point(img.cols/10, img.rows - rect_height), col, -1);
}
imshow( "result", img );
}

View File

@ -1,107 +0,0 @@
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
using namespace std;
using namespace cv;
/** Function Headers */
void detectAndDisplay( Mat frame );
/** Global variables */
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
/** @function main */
int main( int argc, const char** argv )
{
CommandLineParser parser(argc, argv,
"{help h||}"
"{face_cascade|data/haarcascades/haarcascade_frontalface_alt.xml|Path to face cascade.}"
"{eyes_cascade|data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|Path to eyes cascade.}"
"{camera|0|Camera device number.}");
parser.about( "\nThis program demonstrates using the cv::CascadeClassifier class to detect objects (Face + eyes) in a video stream.\n"
"You can use Haar or LBP features.\n\n" );
parser.printMessage();
String face_cascade_name = samples::findFile( parser.get<String>("face_cascade") );
String eyes_cascade_name = samples::findFile( parser.get<String>("eyes_cascade") );
//-- 1. Load the cascades
if( !face_cascade.load( face_cascade_name ) )
{
cout << "--(!)Error loading face cascade\n";
return -1;
};
if( !eyes_cascade.load( eyes_cascade_name ) )
{
cout << "--(!)Error loading eyes cascade\n";
return -1;
};
int camera_device = parser.get<int>("camera");
VideoCapture capture;
//-- 2. Read the video stream
capture.open( camera_device );
if ( ! capture.isOpened() )
{
cout << "--(!)Error opening video capture\n";
return -1;
}
Mat frame;
while ( capture.read(frame) )
{
if( frame.empty() )
{
cout << "--(!) No captured frame -- Break!\n";
break;
}
//-- 3. Apply the classifier to the frame
detectAndDisplay( frame );
if( waitKey(10) == 27 )
{
break; // escape
}
}
return 0;
}
/** @function detectAndDisplay */
void detectAndDisplay( Mat frame )
{
Mat frame_gray;
cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect faces
std::vector<Rect> faces;
face_cascade.detectMultiScale( frame_gray, faces );
for ( size_t i = 0; i < faces.size(); i++ )
{
Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
ellipse( frame, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4 );
Mat faceROI = frame_gray( faces[i] );
//-- In each face, detect eyes
std::vector<Rect> eyes;
eyes_cascade.detectMultiScale( faceROI, eyes );
for ( size_t j = 0; j < eyes.size(); j++ )
{
Point eye_center( faces[i].x + eyes[j].x + eyes[j].width/2, faces[i].y + eyes[j].y + eyes[j].height/2 );
int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
circle( frame, eye_center, radius, Scalar( 255, 0, 0 ), 4 );
}
}
//-- Show what you got
imshow( "Capture - Face detection", frame );
}

View File

@ -1,316 +0,0 @@
// WARNING: this sample is under construction! Use it on your own risk.
#if defined _MSC_VER && _MSC_VER >= 1400
#pragma warning(disable : 4100)
#endif
#include <iostream>
#include <iomanip>
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/cudaobjdetect.hpp"
#include "opencv2/cudaimgproc.hpp"
#include "opencv2/cudawarping.hpp"
using namespace std;
using namespace cv;
using namespace cv::cuda;
static void help()
{
cout << "Usage: ./cascadeclassifier \n\t--cascade <cascade_file>\n\t(<image>|--video <video>|--camera <camera_id>)\n"
"Using OpenCV version " << CV_VERSION << endl << endl;
}
static void convertAndResize(const Mat& src, Mat& gray, Mat& resized, double scale)
{
if (src.channels() == 3)
{
cv::cvtColor( src, gray, COLOR_BGR2GRAY );
}
else
{
gray = src;
}
Size sz(cvRound(gray.cols * scale), cvRound(gray.rows * scale));
if (scale != 1)
{
cv::resize(gray, resized, sz);
}
else
{
resized = gray;
}
}
static void convertAndResize(const GpuMat& src, GpuMat& gray, GpuMat& resized, double scale)
{
if (src.channels() == 3)
{
cv::cuda::cvtColor( src, gray, COLOR_BGR2GRAY );
}
else
{
gray = src;
}
Size sz(cvRound(gray.cols * scale), cvRound(gray.rows * scale));
if (scale != 1)
{
cv::cuda::resize(gray, resized, sz);
}
else
{
resized = gray;
}
}
static void matPrint(Mat &img, int lineOffsY, Scalar fontColor, const string &ss)
{
int fontFace = FONT_HERSHEY_DUPLEX;
double fontScale = 0.8;
int fontThickness = 2;
Size fontSize = cv::getTextSize("T[]", fontFace, fontScale, fontThickness, 0);
Point org;
org.x = 1;
org.y = 3 * fontSize.height * (lineOffsY + 1) / 2;
putText(img, ss, org, fontFace, fontScale, Scalar(0,0,0), 5*fontThickness/2, 16);
putText(img, ss, org, fontFace, fontScale, fontColor, fontThickness, 16);
}
static void displayState(Mat &canvas, bool bHelp, bool bGpu, bool bLargestFace, bool bFilter, double fps)
{
Scalar fontColorRed = Scalar(255,0,0);
Scalar fontColorNV = Scalar(118,185,0);
ostringstream ss;
ss << "FPS = " << setprecision(1) << fixed << fps;
matPrint(canvas, 0, fontColorRed, ss.str());
ss.str("");
ss << "[" << canvas.cols << "x" << canvas.rows << "], " <<
(bGpu ? "GPU, " : "CPU, ") <<
(bLargestFace ? "OneFace, " : "MultiFace, ") <<
(bFilter ? "Filter:ON" : "Filter:OFF");
matPrint(canvas, 1, fontColorRed, ss.str());
// by Anatoly. MacOS fix. ostringstream(const string&) is a private
// matPrint(canvas, 2, fontColorNV, ostringstream("Space - switch GPU / CPU"));
if (bHelp)
{
matPrint(canvas, 2, fontColorNV, "Space - switch GPU / CPU");
matPrint(canvas, 3, fontColorNV, "M - switch OneFace / MultiFace");
matPrint(canvas, 4, fontColorNV, "F - toggle rectangles Filter");
matPrint(canvas, 5, fontColorNV, "H - toggle hotkeys help");
matPrint(canvas, 6, fontColorNV, "1/Q - increase/decrease scale");
}
else
{
matPrint(canvas, 2, fontColorNV, "H - toggle hotkeys help");
}
}
int main(int argc, const char *argv[])
{
if (argc == 1)
{
help();
return -1;
}
if (getCudaEnabledDeviceCount() == 0)
{
return cerr << "No GPU found or the library is compiled without CUDA support" << endl, -1;
}
cv::cuda::printShortCudaDeviceInfo(cv::cuda::getDevice());
string cascadeName;
string inputName;
bool isInputImage = false;
bool isInputVideo = false;
bool isInputCamera = false;
for (int i = 1; i < argc; ++i)
{
if (string(argv[i]) == "--cascade")
cascadeName = argv[++i];
else if (string(argv[i]) == "--video")
{
inputName = argv[++i];
isInputVideo = true;
}
else if (string(argv[i]) == "--camera")
{
inputName = argv[++i];
isInputCamera = true;
}
else if (string(argv[i]) == "--help")
{
help();
return -1;
}
else if (!isInputImage)
{
inputName = argv[i];
isInputImage = true;
}
else
{
cout << "Unknown key: " << argv[i] << endl;
return -1;
}
}
Ptr<cuda::CascadeClassifier> cascade_gpu = cuda::CascadeClassifier::create(cascadeName);
cv::CascadeClassifier cascade_cpu;
if (!cascade_cpu.load(cascadeName))
{
return cerr << "ERROR: Could not load cascade classifier \"" << cascadeName << "\"" << endl, help(), -1;
}
VideoCapture capture;
Mat image;
if (isInputImage)
{
image = imread(inputName);
CV_Assert(!image.empty());
}
else if (isInputVideo)
{
capture.open(inputName);
CV_Assert(capture.isOpened());
}
else
{
capture.open(atoi(inputName.c_str()));
CV_Assert(capture.isOpened());
}
namedWindow("result", 1);
Mat frame, frame_cpu, gray_cpu, resized_cpu, frameDisp;
vector<Rect> faces;
GpuMat frame_gpu, gray_gpu, resized_gpu, facesBuf_gpu;
/* parameters */
bool useGPU = true;
double scaleFactor = 1.0;
bool findLargestObject = false;
bool filterRects = true;
bool helpScreen = false;
for (;;)
{
if (isInputCamera || isInputVideo)
{
capture >> frame;
if (frame.empty())
{
break;
}
}
(image.empty() ? frame : image).copyTo(frame_cpu);
frame_gpu.upload(image.empty() ? frame : image);
convertAndResize(frame_gpu, gray_gpu, resized_gpu, scaleFactor);
convertAndResize(frame_cpu, gray_cpu, resized_cpu, scaleFactor);
TickMeter tm;
tm.start();
if (useGPU)
{
cascade_gpu->setFindLargestObject(findLargestObject);
cascade_gpu->setScaleFactor(1.2);
cascade_gpu->setMinNeighbors((filterRects || findLargestObject) ? 4 : 0);
cascade_gpu->detectMultiScale(resized_gpu, facesBuf_gpu);
cascade_gpu->convert(facesBuf_gpu, faces);
}
else
{
Size minSize = cascade_gpu->getClassifierSize();
cascade_cpu.detectMultiScale(resized_cpu, faces, 1.2,
(filterRects || findLargestObject) ? 4 : 0,
(findLargestObject ? CASCADE_FIND_BIGGEST_OBJECT : 0)
| CASCADE_SCALE_IMAGE,
minSize);
}
for (size_t i = 0; i < faces.size(); ++i)
{
rectangle(resized_cpu, faces[i], Scalar(255));
}
tm.stop();
double detectionTime = tm.getTimeMilli();
double fps = 1000 / detectionTime;
//print detections to console
cout << setfill(' ') << setprecision(2);
cout << setw(6) << fixed << fps << " FPS, " << faces.size() << " det";
if ((filterRects || findLargestObject) && !faces.empty())
{
for (size_t i = 0; i < faces.size(); ++i)
{
cout << ", [" << setw(4) << faces[i].x
<< ", " << setw(4) << faces[i].y
<< ", " << setw(4) << faces[i].width
<< ", " << setw(4) << faces[i].height << "]";
}
}
cout << endl;
cv::cvtColor(resized_cpu, frameDisp, COLOR_GRAY2BGR);
displayState(frameDisp, helpScreen, useGPU, findLargestObject, filterRects, fps);
imshow("result", frameDisp);
char key = (char)waitKey(5);
if (key == 27)
{
break;
}
switch (key)
{
case ' ':
useGPU = !useGPU;
break;
case 'm':
case 'M':
findLargestObject = !findLargestObject;
break;
case 'f':
case 'F':
filterRects = !filterRects;
break;
case '1':
scaleFactor *= 1.05;
break;
case 'q':
case 'Q':
scaleFactor /= 1.05;
break;
case 'h':
case 'H':
helpScreen = !helpScreen;
break;
}
}
return 0;
}

Some files were not shown because too many files have changed in this diff Show More