2011-01-13 14:04:00 +01:00
|
|
|
// WARNING: this sample is under construction! Use it on your own risk.
|
2011-04-07 14:59:01 +02:00
|
|
|
#pragma warning(disable : 4100)
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-04-07 14:59:01 +02:00
|
|
|
#include "cvconfig.h"
|
|
|
|
#include <iostream>
|
|
|
|
#include <iomanip>
|
2011-05-21 20:32:34 +02:00
|
|
|
#include "opencv2/contrib/contrib.hpp"
|
|
|
|
#include "opencv2/objdetect/objdetect.hpp"
|
|
|
|
#include "opencv2/highgui/highgui.hpp"
|
|
|
|
#include "opencv2/imgproc/imgproc.hpp"
|
|
|
|
#include "opencv2/gpu/gpu.hpp"
|
2011-01-13 14:04:00 +01:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace cv;
|
|
|
|
using namespace cv::gpu;
|
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
|
2011-04-07 14:59:01 +02:00
|
|
|
#if !defined(HAVE_CUDA)
|
|
|
|
int main(int argc, const char **argv)
|
|
|
|
{
|
|
|
|
cout << "Please compile the library with CUDA support" << endl;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
2011-01-13 14:04:00 +01:00
|
|
|
void help()
|
|
|
|
{
|
2011-04-04 17:21:58 +02:00
|
|
|
cout << "Usage: ./cascadeclassifier <cascade_file> <image_or_video_or_cameraid>\n"
|
2011-01-13 14:04:00 +01:00
|
|
|
"Using OpenCV version " << CV_VERSION << endl << endl;
|
|
|
|
}
|
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
|
2011-04-07 14:59:01 +02:00
|
|
|
template<class T>
|
|
|
|
void convertAndResize(const T& src, T& gray, T& resized, double scale)
|
2011-01-13 14:04:00 +01:00
|
|
|
{
|
|
|
|
if (src.channels() == 3)
|
2011-04-04 17:21:58 +02:00
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
cvtColor( src, gray, CV_BGR2GRAY );
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
else
|
2011-04-04 17:21:58 +02:00
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
gray = src;
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
|
|
|
|
Size sz(cvRound(gray.cols * scale), cvRound(gray.rows * scale));
|
2011-04-04 17:21:58 +02:00
|
|
|
|
2011-01-13 14:04:00 +01:00
|
|
|
if (scale != 1)
|
2011-04-04 17:21:58 +02:00
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
resize(gray, resized, sz);
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
else
|
2011-04-04 17:21:58 +02:00
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
resized = gray;
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
void matPrint(Mat &img, int lineOffsY, Scalar fontColor, const ostringstream &ss)
|
|
|
|
{
|
2011-04-07 14:59:01 +02:00
|
|
|
int fontFace = FONT_HERSHEY_DUPLEX;
|
|
|
|
double fontScale = 0.8;
|
2011-04-04 17:21:58 +02:00
|
|
|
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;
|
2011-04-07 14:59:01 +02:00
|
|
|
putText(img, ss.str(), org, fontFace, fontScale, CV_RGB(0,0,0), 5*fontThickness/2, 16);
|
|
|
|
putText(img, ss.str(), org, fontFace, fontScale, fontColor, fontThickness, 16);
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
|
|
|
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
void displayState(Mat &canvas, bool bHelp, bool bGpu, bool bLargestFace, bool bFilter, double fps)
|
|
|
|
{
|
|
|
|
Scalar fontColorRed = CV_RGB(255,0,0);
|
|
|
|
Scalar fontColorNV = CV_RGB(118,185,0);
|
|
|
|
|
|
|
|
ostringstream ss;
|
2011-04-07 14:59:01 +02:00
|
|
|
ss << "FPS = " << setprecision(1) << fixed << fps;
|
|
|
|
matPrint(canvas, 0, fontColorRed, ss);
|
|
|
|
ss.str("");
|
2011-04-04 17:21:58 +02:00
|
|
|
ss << "[" << canvas.cols << "x" << canvas.rows << "], " <<
|
|
|
|
(bGpu ? "GPU, " : "CPU, ") <<
|
|
|
|
(bLargestFace ? "OneFace, " : "MultiFace, ") <<
|
2011-04-07 14:59:01 +02:00
|
|
|
(bFilter ? "Filter:ON" : "Filter:OFF");
|
|
|
|
matPrint(canvas, 1, fontColorRed, ss);
|
2011-04-04 17:21:58 +02:00
|
|
|
|
|
|
|
if (bHelp)
|
|
|
|
{
|
2011-04-07 14:59:01 +02:00
|
|
|
matPrint(canvas, 2, fontColorNV, ostringstream("Space - switch GPU / CPU"));
|
|
|
|
matPrint(canvas, 3, fontColorNV, ostringstream("M - switch OneFace / MultiFace"));
|
|
|
|
matPrint(canvas, 4, fontColorNV, ostringstream("F - toggle rectangles Filter"));
|
|
|
|
matPrint(canvas, 5, fontColorNV, ostringstream("H - toggle hotkeys help"));
|
|
|
|
matPrint(canvas, 6, fontColorNV, ostringstream("1/Q - increase/decrease scale"));
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-04-07 14:59:01 +02:00
|
|
|
matPrint(canvas, 2, fontColorNV, ostringstream("H - toggle hotkeys help"));
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, const char *argv[])
|
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
if (argc != 3)
|
2011-04-04 17:21:58 +02:00
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
return help(), -1;
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
if (getCudaEnabledDeviceCount() == 0)
|
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
return cerr << "No GPU found or the library is compiled without GPU support" << endl, -1;
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
|
|
|
|
VideoCapture capture;
|
2011-04-04 17:21:58 +02:00
|
|
|
|
2011-01-13 14:04:00 +01:00
|
|
|
string cascadeName = argv[1];
|
|
|
|
string inputName = argv[2];
|
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
CascadeClassifier_GPU cascade_gpu;
|
|
|
|
if (!cascade_gpu.load(cascadeName))
|
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
return cerr << "ERROR: Could not load cascade classifier \"" << cascadeName << "\"" << endl, help(), -1;
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
CascadeClassifier cascade_cpu;
|
|
|
|
if (!cascade_cpu.load(cascadeName))
|
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
return cerr << "ERROR: Could not load cascade classifier \"" << cascadeName << "\"" << endl, help(), -1;
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Mat image = imread(inputName);
|
|
|
|
|
|
|
|
if (image.empty())
|
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
if (!capture.open(inputName))
|
|
|
|
{
|
2011-04-07 14:59:01 +02:00
|
|
|
int camid = -1;
|
|
|
|
istringstream iss(inputName);
|
|
|
|
iss >> camid;
|
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
if (!capture.open(camid))
|
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
cout << "Can't open source" << endl;
|
2011-04-04 17:21:58 +02:00
|
|
|
return help(), -1;
|
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
}
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
namedWindow("result", 1);
|
|
|
|
|
2011-01-13 14:04:00 +01:00
|
|
|
Mat frame, frame_cpu, gray_cpu, resized_cpu, faces_downloaded, frameDisp;
|
|
|
|
vector<Rect> facesBuf_cpu;
|
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
GpuMat frame_gpu, gray_gpu, resized_gpu, facesBuf_gpu;
|
|
|
|
|
2011-01-13 14:04:00 +01:00
|
|
|
/* parameters */
|
|
|
|
bool useGPU = true;
|
2011-04-04 17:21:58 +02:00
|
|
|
double scaleFactor = 1.0;
|
|
|
|
bool findLargestObject = false;
|
|
|
|
bool filterRects = true;
|
|
|
|
bool helpScreen = false;
|
|
|
|
|
2011-01-13 14:04:00 +01:00
|
|
|
int detections_num;
|
2011-04-04 17:21:58 +02:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (capture.isOpened())
|
2011-01-13 14:04:00 +01:00
|
|
|
{
|
2011-04-04 17:21:58 +02:00
|
|
|
capture >> frame;
|
|
|
|
if (frame.empty())
|
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
break;
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
(image.empty() ? frame : image).copyTo(frame_cpu);
|
2011-04-04 17:21:58 +02:00
|
|
|
frame_gpu.upload(image.empty() ? frame : image);
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
convertAndResize(frame_gpu, gray_gpu, resized_gpu, scaleFactor);
|
|
|
|
convertAndResize(frame_cpu, gray_cpu, resized_cpu, scaleFactor);
|
|
|
|
|
|
|
|
TickMeter tm;
|
|
|
|
tm.start();
|
2011-01-13 14:04:00 +01:00
|
|
|
|
|
|
|
if (useGPU)
|
|
|
|
{
|
2011-04-04 17:21:58 +02:00
|
|
|
cascade_gpu.visualizeInPlace = true;
|
|
|
|
cascade_gpu.findLargestObject = findLargestObject;
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-04-07 14:59:01 +02:00
|
|
|
detections_num = cascade_gpu.detectMultiScale(resized_gpu, facesBuf_gpu, 1.2,
|
|
|
|
(filterRects || findLargestObject) ? 4 : 0);
|
2011-01-13 14:04:00 +01:00
|
|
|
facesBuf_gpu.colRange(0, detections_num).download(faces_downloaded);
|
|
|
|
}
|
2011-04-04 17:21:58 +02:00
|
|
|
else
|
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
Size minSize = cascade_gpu.getClassifierSize();
|
2011-04-07 14:59:01 +02:00
|
|
|
cascade_cpu.detectMultiScale(resized_cpu, facesBuf_cpu, 1.2,
|
|
|
|
(filterRects || findLargestObject) ? 4 : 0,
|
|
|
|
(findLargestObject ? CV_HAAR_FIND_BIGGEST_OBJECT : 0)
|
|
|
|
| CV_HAAR_SCALE_IMAGE,
|
|
|
|
minSize);
|
2011-01-13 14:04:00 +01:00
|
|
|
detections_num = (int)facesBuf_cpu.size();
|
|
|
|
}
|
|
|
|
|
2011-04-07 14:59:01 +02:00
|
|
|
if (!useGPU && detections_num)
|
2011-04-04 17:21:58 +02:00
|
|
|
{
|
2011-04-07 14:59:01 +02:00
|
|
|
for (int i = 0; i < detections_num; ++i)
|
2011-01-13 14:04:00 +01:00
|
|
|
{
|
2011-04-07 14:59:01 +02:00
|
|
|
rectangle(resized_cpu, facesBuf_cpu[i], Scalar(255));
|
2011-01-13 14:04:00 +01:00
|
|
|
}
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
if (useGPU)
|
|
|
|
{
|
|
|
|
resized_gpu.download(resized_cpu);
|
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
tm.stop();
|
|
|
|
double detectionTime = tm.getTimeMilli();
|
|
|
|
double fps = 1000 / detectionTime;
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
//print detections to console
|
|
|
|
cout << setfill(' ') << setprecision(2);
|
|
|
|
cout << setw(6) << fixed << fps << " FPS, " << detections_num << " det";
|
|
|
|
if ((filterRects || findLargestObject) && detections_num > 0)
|
|
|
|
{
|
|
|
|
Rect *faceRects = useGPU ? faces_downloaded.ptr<Rect>() : &facesBuf_cpu[0];
|
|
|
|
for (int i = 0; i < min(detections_num, 2); ++i)
|
|
|
|
{
|
|
|
|
cout << ", [" << setw(4) << faceRects[i].x
|
|
|
|
<< ", " << setw(4) << faceRects[i].y
|
|
|
|
<< ", " << setw(4) << faceRects[i].width
|
|
|
|
<< ", " << setw(4) << faceRects[i].height << "]";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cout << endl;
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
cvtColor(resized_cpu, frameDisp, CV_GRAY2BGR);
|
|
|
|
displayState(frameDisp, helpScreen, useGPU, findLargestObject, filterRects, fps);
|
|
|
|
imshow("result", frameDisp);
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-04-04 17:21:58 +02:00
|
|
|
int key = waitKey(5);
|
|
|
|
if (key == 27)
|
|
|
|
{
|
2011-01-13 14:04:00 +01:00
|
|
|
break;
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
2011-01-13 14:04:00 +01:00
|
|
|
|
2011-01-17 18:32:50 +01:00
|
|
|
switch ((char)key)
|
2011-01-13 14:04:00 +01:00
|
|
|
{
|
2011-04-04 17:21:58 +02:00
|
|
|
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;
|
2011-01-13 14:04:00 +01:00
|
|
|
}
|
2011-04-04 17:21:58 +02:00
|
|
|
}
|
|
|
|
|
2011-01-13 14:04:00 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2011-04-07 14:59:01 +02:00
|
|
|
|
|
|
|
#endif //!defined(HAVE_CUDA)
|