OPENCV例子opencv-4.5.5\samples\gpu\cascadeclassifier.cpp的代码分析

该示例用来演示CascadeClassifier(级联分类器)的使用,示例中注明了示例处于“建设中”,运行可能有问题。

代码中函数的调用关系:

 

main函数的调用关系:

 

main函数的流程图:

 

main函数的UML逻辑图:

 

示例的源代码如下:

// 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");//空格 - 切换 GPU / CPU

        matPrint(canvas, 3, fontColorNV, "M - switch OneFace / MultiFace");//M 单面/多面

        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;// 未找到 GPU 或在没有 CUDA 支持的情况下编译的库

    }

    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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qqq9668

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值