溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Qt怎么實(shí)現(xiàn)實(shí)時(shí)人臉框

發(fā)布時(shí)間:2021-12-15 10:13:21 來(lái)源:億速云 閱讀:254 作者:iii 欄目:互聯(lián)網(wǎng)科技

這篇文章主要介紹“Qt怎么實(shí)現(xiàn)實(shí)時(shí)人臉框”,在日常操作中,相信很多人在Qt怎么實(shí)現(xiàn)實(shí)時(shí)人臉框問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Qt怎么實(shí)現(xiàn)實(shí)時(shí)人臉框”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

一、前言

在人臉識(shí)別到以后,需要在實(shí)時(shí)視頻上將所有人臉框繪制出來(lái),一把來(lái)說(shuō)識(shí)別人臉會(huì)有多種選擇,一個(gè)是識(shí)別最大人臉,這種場(chǎng)景主要用于刷臉門禁,還有一種是識(shí)別所有人臉,這種場(chǎng)景主要用于人臉識(shí)別攝像機(jī),就是將畫面中的所有人臉識(shí)別出來(lái)發(fā)給服務(wù)器,人臉框的數(shù)據(jù)主要是四個(gè)參數(shù),左上角和右下角的位置,也可以說(shuō)是x、y、width、height,可能有些做的比較好的還有傾斜角度,這個(gè)意義不是很大,人臉識(shí)別的速度一般都是飛快的,就算你用學(xué)習(xí)上用的opencv做識(shí)別也是非常快的,基本上都是毫秒級(jí)的響應(yīng),主要的耗時(shí)操作在特征值的提取,所以一般要求能夠響應(yīng)每個(gè)通道每秒鐘25幀-30幀的畫面繪制+人臉框的繪制,當(dāng)然人臉框的數(shù)據(jù)可能會(huì)有多個(gè)。

用Qt來(lái)繪制人臉框,核心就是一個(gè)函數(shù),調(diào)用QPainter的drawRect方法,傳入?yún)^(qū)域即可,如果花哨點(diǎn)的話還可以設(shè)置邊框的粗細(xì)和顏色、圓角角度等,注意圓角角度使用的是drawRoundedRect而不是drawRoundRect,很多人這里會(huì)搞錯(cuò)哦。近期接觸的項(xiàng)目對(duì)人臉框的要求越來(lái)越多,之前是讓用戶自己拿到圖片來(lái)繪制,近期索性直接將這個(gè)功能內(nèi)置到視頻控件中(視頻控件封裝了多種內(nèi)核版本,有ffmpeg、vlc、mpv、海康sdk等),提供了可設(shè)置邊框粗細(xì)、顏色,傳入人臉框區(qū)域集合的接口,用戶只要自己的算法分析拿到人臉的區(qū)域集合(用戶是上帝,用戶的需求就是我的需求),通過(guò)setFaceRects函數(shù)設(shè)置即可,如果要清空人臉,只要設(shè)置人臉框區(qū)域集合為空即可??傮w測(cè)試下來(lái)速度非??欤梢院雎?,采用的QOPenGLWidget繪制的實(shí)時(shí)圖像,也支持人臉框的繪制。

二、功能特點(diǎn)

  1. 支持的功能包括人臉識(shí)別、人臉比對(duì)、人臉?biāo)阉?、活體檢測(cè)等。

  2. 在線版還支持身份證、駕駛證、行駛證、銀行卡等識(shí)別。

  3. 在線版的協(xié)議支持百度、曠視,離線版的支持百度,可定制。

  4. 除了支持X86架構(gòu),還支持嵌入式linux比如contex-A9、樹(shù)莓派等。

  5. 每個(gè)功能的執(zhí)行除了返回結(jié)果還返回執(zhí)行用時(shí)時(shí)間。

  6. 多線程處理,通過(guò)type控制當(dāng)前處理類型。

  7. 支持單張圖片檢索相似度最高的圖片。

  8. 支持指定目錄圖片用來(lái)生成人臉特征值文件。

  9. 可設(shè)置等待處理圖片隊(duì)列中的數(shù)量。

  10. 每次執(zhí)行都有成功或者失敗的信號(hào)返回。

  11. 人臉?biāo)阉鞯姆祷亟Y(jié)果包含了原圖+最大相似度圖+相似度等。

  12. 人臉比對(duì)同時(shí)支持兩張圖片和兩個(gè)特征值比對(duì)。

  13. 相關(guān)功能自定義一套協(xié)議用于客戶端和服務(wù)端,可以通過(guò)TCP通信進(jìn)行交互。

  14. 自定義人臉識(shí)別協(xié)議非常適用于中心一臺(tái)服務(wù)器,現(xiàn)場(chǎng)若干設(shè)備請(qǐng)求的場(chǎng)景。

  15. 每個(gè)模塊全部是獨(dú)立的一個(gè)類,代碼整潔、注釋完善。

三、效果圖

Qt怎么實(shí)現(xiàn)實(shí)時(shí)人臉框

四、核心代碼

bool FFmpegWidget::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == osdWidget && event->type() == QEvent::Paint) {
        if (drawImage) {
            QPainter painter;
            painter.begin(osdWidget);
            painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);

            //繪制邊框
            drawBorder(&painter);
            if (thread->getIsInit()) {
                //繪制背景圖片
                drawImg(&painter, image);
                //繪制人臉框
                drawFace(&painter);
                //繪制標(biāo)簽
                drawOSD(&painter, osd1Visible, osd1FontSize, osd1Text, osd1Color, osd1Image, osd1Format, osd1Position);
                drawOSD(&painter, osd2Visible, osd2FontSize, osd2Text, osd2Color, osd2Image, osd2Format, osd2Position);
            } else {
                //繪制背景
                if (!isDrag) {
                    drawBg(&painter);
                }
            }

            painter.end();
        }
    }

    return QWidget::eventFilter(watched, event);
}

void FFmpegWidget::drawBorder(QPainter *painter)
{
    if (borderWidth == 0) {
        return;
    }

    painter->save();
    QPen pen;
    pen.setWidth(borderWidth);
    pen.setColor(hasFocus() ? focusColor : borderColor);
    painter->setPen(pen);
    painter->drawRect(rect());
    painter->restore();
}

void FFmpegWidget::drawBg(QPainter *painter)
{
    painter->save();

    //背景圖片為空則繪制文字,否則繪制背景圖片
    if (bgImage.isNull()) {
        painter->setFont(this->font());
        painter->setPen(palette().foreground().color());
        painter->drawText(rect(), Qt::AlignCenter, bgText);
    } else {
        //居中繪制
        int x = rect().center().x() - bgImage.width() / 2;
        int y = rect().center().y() - bgImage.height() / 2;
        QPoint point(x, y);
        painter->drawImage(point, bgImage);
    }

    painter->restore();
}

void FFmpegWidget::drawImg(QPainter *painter, QImage img)
{
    if (img.isNull()) {
        return;
    }

    painter->save();

    int offset = borderWidth * 1 + 0;
    img = img.scaled(width() - offset, height() - offset, Qt::KeepAspectRatio, Qt::SmoothTransformation);

    if (fillImage) {
        QRect rect(offset / 2, offset / 2, width() - offset, height() - offset);
        painter->drawImage(rect, img);
    } else {
        //按照比例自動(dòng)居中繪制
        int x = rect().center().x() - img.width() / 2;
        int y = rect().center().y() - img.height() / 2;
        QPoint point(x, y);
        painter->drawImage(point, img);
    }

    painter->restore();
}

void FFmpegWidget::drawFace(QPainter *painter)
{
    if (faceRects.count() == 0) {
        return;
    }

    painter->save();

    //人臉邊框的顏色
    QPen pen;
    pen.setWidth(faceBorder);
    pen.setColor(faceColor);
    painter->setPen(pen);

    //逐個(gè)取出人臉框區(qū)域進(jìn)行繪制
    foreach (QRect rect, faceRects) {
        painter->drawRect(rect);
    }

    painter->restore();
}

void FFmpegWidget::drawOSD(QPainter *painter,
                           bool osdVisible,
                           int osdFontSize,
                           const QString &osdText,
                           const QColor &osdColor,
                           const QImage &osdImage,
                           const FFmpegWidget::OSDFormat &osdFormat,
                           const FFmpegWidget::OSDPosition &osdPosition)
{
    if (!osdVisible) {
        return;
    }

    painter->save();

    //標(biāo)簽位置盡量偏移多一點(diǎn)避免遮擋
    QRect osdRect(rect().x() + (borderWidth * 2), rect().y() + (borderWidth * 2), width() - (borderWidth * 5), height() - (borderWidth * 5));
    int flag = Qt::AlignLeft | Qt::AlignTop;
    QPoint point = QPoint(osdRect.x(), osdRect.y());

    if (osdPosition == OSDPosition_Left_Top) {
        flag = Qt::AlignLeft | Qt::AlignTop;
        point = QPoint(osdRect.x(), osdRect.y());
    } else if (osdPosition == OSDPosition_Left_Bottom) {
        flag = Qt::AlignLeft | Qt::AlignBottom;
        point = QPoint(osdRect.x(), osdRect.height() - osdImage.height());
    } else if (osdPosition == OSDPosition_Right_Top) {
        flag = Qt::AlignRight | Qt::AlignTop;
        point = QPoint(osdRect.width() - osdImage.width(), osdRect.y());
    } else if (osdPosition == OSDPosition_Right_Bottom) {
        flag = Qt::AlignRight | Qt::AlignBottom;
        point = QPoint(osdRect.width() - osdImage.width(), osdRect.height() - osdImage.height());
    }

    if (osdFormat == OSDFormat_Image) {
        painter->drawImage(point, osdImage);
    } else {
        QDateTime now = QDateTime::currentDateTime();
        QString text = osdText;
        if (osdFormat == OSDFormat_Date) {
            text = now.toString("yyyy-MM-dd");
        } else if (osdFormat == OSDFormat_Time) {
            text = now.toString("HH:mm:ss");
        } else if (osdFormat == OSDFormat_DateTime) {
            text = now.toString("yyyy-MM-dd HH:mm:ss");
        }

        //設(shè)置顏色及字號(hào)
        QFont font;
        font.setPixelSize(osdFontSize);
        painter->setPen(osdColor);
        painter->setFont(font);

        painter->drawText(osdRect, flag, text);
    }

    painter->restore();
}

到此,關(guān)于“Qt怎么實(shí)現(xiàn)實(shí)時(shí)人臉框”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

qt
AI