#include "InteractiveFace.h" InteractiveFace::InteractiveFace(QObject *parent) : QQuickImageProvider(QQuickImageProvider::Image) { initEngine(); if (hasCamera()) { // initCamera(); } // 图像取1s 10帧 m_timerId = startTimer(100); } bool InteractiveFace::hasCamera() { return !QMediaDevices::videoInputs().isEmpty(); } InteractiveFace::~InteractiveFace() { destroyEngine(); } void InteractiveFace::initEngine() { const char* appId = "FTN3G4pk8n2RKwjD955sRapRjbYQFefwhHd4sBZMYEz6"; const char* sdkKey = "BjJomNU2bQc2SYhT7NNqwvFd9zfc72Q7nneh75r3NT3x"; const char* licenseFilePath = "./offlineLicense.dat"; // 超过5次不再尝试获取授权文件 int iLoopCount = 5; do{ MPChar activeDeviceInfo; ASFGetActiveDeviceInfo(&activeDeviceInfo); ASF_ActiveFileInfo activeFileInfo; MRESULT res = -1; if ((res = ASFGetActiveFileInfo(&activeFileInfo)) == MOK) { qDebug() << "获取版本信息成功"; break; } else{ FileLogger::writeToFile("deviceInfo","ArcSoftDeviceInfo.txt",activeDeviceInfo,FileLogger::WriteMode::OVERWRITE); if(res == 0x1601A){ if((res = ASFOfflineActivation((MPChar)licenseFilePath)) == MOK) { qDebug() << "授权成功"; } } } break; }while(iLoopCount--); // 初始化引擎 MRESULT res = ASFInitEngine(ASF_DETECT_MODE_VIDEO, ASF_OP_ALL_OUT, 1, ASF_FACE_DETECT | ASF_FACERECOGNITION, &m_engine); if (res != MOK) { qDebug() << " 初始化引擎失败" << res; } } void InteractiveFace::destroyEngine() { } void InteractiveFace::cameraPlay() { // 如果相机不是播放状态 if (!m_camera.isActive()) { QCameraDevice cameraDevice = QMediaDevices::defaultVideoInput(); if (cameraDevice.isNull()) { qWarning() << "系统中没有检测到任何摄像机设备"; return; } m_camera.setCameraDevice(cameraDevice); // 确保图像宽度是4的倍数(虹软人脸识别要求) if (m_camera.cameraFormat().resolution().width() % 4 != 0) { QList cameraFormats = cameraDevice.videoFormats(); for (int i = 0; i < cameraFormats.size(); ++i) { const QCameraFormat &cameraFormat = cameraFormats.at(i); if (cameraFormat.resolution().width() % 4 == 0) { m_camera.setCameraFormat(cameraFormat); break; } } } m_session.setCamera(&m_camera); m_session.setVideoSink(&m_videoSink); m_camera.start(); } } void InteractiveFace::cameraStop() { if (m_camera.isActive()) { m_camera.stop(); m_camera.setActive(false); m_camera.setCameraDevice(QCameraDevice()); m_session.setCamera(nullptr); m_session.setVideoSink(nullptr); } } void InteractiveFace::initCamera() { m_camera.setCameraDevice(QMediaDevices::defaultVideoInput()); QCameraDevice device = QMediaDevices::defaultVideoInput(); QList formats = device.videoFormats(); // 选择最适合的格式 for (const QCameraFormat &format : formats) { // qDebug() << "fps---" << format.maxFrameRate() << format.resolution().width() << format.resolution().height(); if (format.maxFrameRate() >= 10.0 && format.resolution().width() % 4 == 0) { m_camera.setCameraFormat(format); break; } } m_session.setCamera(&m_camera); m_session.setVideoSink(&m_videoSink); } void InteractiveFace::destroyCamera() { } QString InteractiveFace::getImageUrl() { // image://InteractiveFaceImage/(0-9999) return QString("image://") + QString(INTERACTIVE_FACE_IMAGE_URL) + QString("/") + // 取随机数,确保图片刷新(Qt机制,两次url地址相同,图片不会显示) QString::number(QRandomGenerator::global()->bounded(10000)); } // 设置图像采集回调 void InteractiveFace::setCameraImageGatherCallBack(QJSValue callback) { m_imageGatherCallback = callback; } // 设置发现人脸回调 void InteractiveFace::setCameraImageAppearCallBack(QJSValue callback) { m_imageAppearCallback = callback; } // 设置人脸停留回调 void InteractiveFace::setCameraImageRemainCallBack(QJSValue callback) { m_imageRemainCallback = callback; } void InteractiveFace::setCameraImageCallBack(QJSValue gatherCallback, QJSValue appearCallback, QJSValue remainCallback) { m_imageGatherCallback = gatherCallback; m_imageAppearCallback = appearCallback; m_imageRemainCallback = remainCallback; } void InteractiveFace::setCallBackFaceStatus(QJSValue isAppearCallback) { m_isAppearCallback = isAppearCallback; } void InteractiveFace::cameraImagePlay() { if (!hasCamera()) { return; } if (!m_camera.isActive()) { cameraPlay(); m_laseEpoch = 0; m_laseCount = 0; m_FrameId = 0; } } void InteractiveFace::cameraImageStop() { if (!hasCamera()) { return; } cameraStop(); } QImage InteractiveFace::requestImage(const QString &, QSize *, const QSize &) { return m_image; } void InteractiveFace::timerEvent(QTimerEvent *event) { if (event->timerId() == m_timerId) { if (!hasCamera()) { return; } if (m_camera.isActive()) { QMutexLocker locker(&m_mutex); QVideoFrame currentFormat = m_videoSink.videoFrame(); QImage image; // 图像 QPainter painter; // 画笔 // 过滤无效帧, 前10帧不做处理 if(++m_FrameId <= 30) { m_image = image.copy(); if (m_imageGatherCallback.isCallable()) { QJSValueList args; args << getImageUrl(); m_imageGatherCallback.call(args); } return; } if (currentFormat.isValid()) { if (currentFormat.map(QVideoFrame::ReadOnly)) { image = currentFormat.toImage(); // image = image.scaled(QSize(800, 600), Qt::KeepAspectRatio, Qt::SmoothTransformation); } currentFormat.unmap(); } if (!image.isNull()) { // image底部框 painter.begin(&image); painter.setRenderHint(QPainter::Antialiasing); painter.setFont(QFont("Arial", 24)); painter.setBrush(QColor(255, 255, 255, 127)); painter.setPen(Qt::NoPen); painter.drawRect(QRect(0, image.height() - 50, image.width(), 50)); QImage convertedImage = image.convertToFormat(QImage::Format_RGB888); ASVLOFFSCREEN offscreen = {0}; offscreen.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8; offscreen.i32Width = convertedImage.width(); offscreen.i32Height = convertedImage.height(); offscreen.pi32Pitch[0] = convertedImage.bytesPerLine(); offscreen.ppu8Plane[0] = (MUInt8*)convertedImage.bits(); if (offscreen.ppu8Plane[0]) { if (m_engine != NULL) { ASF_MultiFaceInfo detectedFaces = {0}; MRESULT res = ASFDetectFaces(m_engine, offscreen.i32Width, offscreen.i32Height, offscreen.u32PixelArrayFormat, offscreen.ppu8Plane[0], &detectedFaces); if (res != MOK) { qDebug() << "检测人脸失败" << res; } bool isAppear; // 获取第一个人脸 if (res == MOK && detectedFaces.faceNum == 1) { isAppear = true; if (m_laseCount <= 0) { m_laseCount = 1; m_laseEpoch = QDateTime::currentSecsSinceEpoch(); } if (m_imageAppearCallback.isCallable()) { m_image = image.copy(); QJSValueList args; args << getImageUrl(); m_imageAppearCallback.call(args); } MRECT mrect = detectedFaces.faceRect[0]; qint64 epoch = QDateTime::currentSecsSinceEpoch() - m_laseEpoch; if (epoch <= 1) { painter.setPen(QPen(Qt::blue, 3)); painter.drawText(QRect(0, image.height() - 50, image.width(), 50), Qt::AlignCenter, QString("检测到人脸,即将拍摄").arg(epoch)); // 绘制人脸框 painter.setPen(QPen(Qt::green, 2)); painter.setBrush(Qt::NoBrush); painter.drawRect(QRect(mrect.left, mrect.top, mrect.right - mrect.left, mrect.bottom - mrect.top)); } else if (epoch > 1 && epoch <= 4) { painter.setPen(QPen(Qt::blue, 3)); painter.drawText(QRect(0, image.height() - 50, image.width(), 50), Qt::AlignCenter, QString("%1").arg(5 - epoch)); // 绘制人脸框 painter.setPen(QPen(Qt::green, 2)); painter.setBrush(Qt::NoBrush); painter.drawRect(QRect(mrect.left, mrect.top, mrect.right - mrect.left, mrect.bottom - mrect.top)); } else if (epoch >= 5) { if (m_imageRemainCallback.isCallable()) { QJSValueList args; args << getImageUrl(); m_imageRemainCallback.call(args); } } } else if (res == MOK && detectedFaces.faceNum >= 2) { isAppear = true; m_laseCount--; painter.setPen(QPen(Qt::red, 3)); painter.drawText(QRect(0, image.height() - 50, image.width(), 50), Qt::AlignCenter, QString("请保持单人入镜,请保持光线充足")); } else { isAppear = false; m_laseCount--; painter.setPen(QPen(Qt::red, 3)); painter.drawText(QRect(0, image.height() - 50, image.width(), 50), Qt::AlignCenter, QString("请保持真人操作,请保持光线充足")); } if (m_isAppearCallback.isCallable()) { QJSValueList args; args << isAppear; m_isAppearCallback.call(args); } } } painter.end(); m_image = image.copy(); if (m_imageGatherCallback.isCallable()) { QJSValueList args; args << getImageUrl(); m_imageGatherCallback.call(args); } } } } } // 获取图像 QImage InteractiveFace::getImage() { QMutexLocker locker(&m_mutex); return m_image.copy(); }