seetaface6的编译安装过程

我的环境是MSVC x64,编译工具:CMake
源代码下载地址:https://github.com/SeetaFace6Open/index

编译顺序说明

OpenRoleZoo 为常用操作的集合,SeetaAuthorize 为模型解析工程,
TenniS 为前向计算框架。需要重点说明的是,
此次 TenniS 同时放出了 GPU 计算源码,可以编译出 GPU 版本进行使用。上述三个模块为基础模块,
各个 SDK 的编译均依赖上述模块,因此需要优先编译出 OpenRoleZoo, SeetaAuthorize 和 TenniS,
然后再进行其他 SDK 模块的编译。

编译OpenRoleZoo模块
使用cmake开始编译OpenRoleZoo,出现了cmake 编译版本不对的错误:

CMake Error at CMakeLists.txt:1 (cmake_minimum_required):
  Compatibility with CMake < 3.5 has been removed from CMake.

  Update the VERSION argument <min> value.  Or, use the <min>...<max> syntax
  to tell CMake that the project requires at least <min> but has been updated
  to work with policies introduced by <max> or earlier.

  Or, add -DCMAKE_POLICY_VERSION_MINIMUM=3.5 to try configuring anyway.


Configuring incomplete, errors occurred!

解决方法:

直接去改cmake的编译版本依赖
cmake_minimum_required(VERSION 3.5...3.31)

记得修改安装路径,不然会出现等会install的时候,没有权限的错误:

错误	MSB3073	命令“setlocal...”

尽管如此,还是会出现错误:

找不到 std::function...

解决方法:

用任何文本编辑器打开 OpenRoleZoo/include/orz/mem/pot.h 文件,在文件开头的 #include 部分,添加一行 #include <functional>

修改后的文件开头看起来像这样:

//
// Created by Lby on 2017/8/12.
//

#ifndef ORZ_MEM_POT_H
#define ORZ_MEM_POT_H

#include <functional>  //  就是添加这一行
#include <mutex>
#include <memory>

// ... 文件剩余内容保持不变

终于可以安心的生成和install了
这一步到此为止

编译SeetaAuthorize模块

出现了以下错误:

Selecting Windows SDK version 10.0.26100.0 to target Windows 10.0.26200.
Platform: x64
Configuration: Release
Build with ORZ
E:/seetaface/orc
E:/seetaface/orc/lib/x64
Configuring done (0.0s)
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
LIB_ORZ_PATH
    linked by target "SeetaAuthorize" in directory E:/seetaface/index/SeetaAuthorize

Generating done (0.0s)

解决方法:
cmake设置
LIB_ORZ_PATH为你的lib路径,例如我的路径为:E:/seetaface/orc/lib/ORZ_static.lib

编译TenniS模块
CMAKE_INSTALL_PREFIX 不要设置c盘基本就可以了

编译FaceBoxes模块-用于检测人脸
配置好SeetaAuthorize、TenniS的路径即可,编译完后,可以使用以下代码测试是否能正常检测到人脸:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <seeta/FaceDetector.h> 
#include <seeta/Common/Struct.h>

int main() {
    try {
        // 1. 设置FaceBoxes模型路径
        // 请根据您的实际模型文件路径修改
        seeta::ModelSetting::Device device = seeta::ModelSetting::CPU;
        int id = 0;

        // 模型文件路径 - 请根据实际情况修改
        std::string model_path = "models/face_detector.csta";

        // 2. 初始化人脸检测器
        seeta::ModelSetting setting(model_path, device, id);
        seeta::FaceDetector detector(setting);

        // 3. 设置检测器参数(可选)
        detector.set(seeta::FaceDetector::PROPERTY_MIN_FACE_SIZE, 20);      // 最小人脸尺寸
        detector.set(seeta::FaceDetector::PROPERTY_THRESHOLD, 0.9);         // 检测阈值
        detector.set(seeta::FaceDetector::PROPERTY_MAX_IMAGE_WIDTH, 2000);  // 最大图像宽度
        detector.set(seeta::FaceDetector::PROPERTY_MAX_IMAGE_HEIGHT, 2000); // 最大图像高度

        std::cout << "人脸检测器初始化成功!" << std::endl;

        // 4. 打开摄像头
        cv::VideoCapture cap(0);
        if (!cap.isOpened()) {
            std::cerr << "错误:无法打开摄像头!" << std::endl;
            return -1;
        }

        std::cout << "摄像头已打开,按 'ESC' 键退出程序" << std::endl;
        std::cout << "按 's' 键保存当前帧" << std::endl;

        cv::Mat frame;
        int frame_count = 0;
        int64_t total_time = 0;

        while (true) {
            cap >> frame;
            if (frame.empty()) {
                std::cerr << "警告:读取空帧" << std::endl;
                continue;
            }

            // 5. 准备SeetaImage数据
            cv::Mat image = frame.clone();

            SeetaImageData simg;
            simg.data = image.data;
            simg.width = image.cols;
            simg.height = image.rows;
            simg.channels = image.channels();

            // 6. 执行人脸检测(计时)
            int64_t start_time = cv::getTickCount();

            auto faces = detector.detect(simg);

            int64_t end_time = cv::getTickCount();
            double detect_time = (end_time - start_time) * 1000.0 / cv::getTickFrequency();
            total_time += detect_time;

            // 7. 绘制检测结果
            for (int i = 0; i < faces.size; ++i) {
                auto& face = faces.data[i];
                auto& pos = face.pos;

                cv::rectangle(frame, cv::Rect(pos.x, pos.y, pos.width, pos.height), CV_RGB(0, 128, 128), 3);
            }




            // 9. 显示画面
            cv::imshow("Face Detection - SeetaFace6", frame);

            // 10. 键盘控制
            char key = cv::waitKey(1);
            if (key == 27) {  // ESC键
                break;
            }
            else if (key == 's' || key == 'S') {  // 保存图片
                std::string filename = cv::format("face_detection_%d.jpg", frame_count);
                cv::imwrite(filename, frame);
                std::cout << "图片已保存: " << filename << std::endl;
            }
        }

        // 11. 输出平均检测时间
        std::cout << "程序运行结束" << std::endl;
        std::cout << "总检测帧数: " << frame_count << std::endl;
        std::cout << "平均检测时间: " << total_time / frame_count << " ms" << std::endl;

    }
    catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << std::endl;
        return -1;
    }


    cv::destroyAllWindows();

    return 0;
}

编译landmarker模块-用于检测特征点
配置好SeetaAuthorize、TenniS的路径即可

编译FaceRecognizer6模块
注意设置SeetaAuthorize的一些配置路径(TenniS同理)
SeetaAuthorize_DIR 设置为install后的cmake路径
SeetaAuthorize_INCLUDE_DIR 设置为install后的include路径
cmake最终生成成功如下(无视Warning):

bb
install成功如下

cc

最终代码如下:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <seeta/FaceDetector.h> 
#include <seeta/FaceRecognizer.h>
#include <seeta/FaceLandmarker.h>  // 添加关键点检测器头文件
#include <seeta/Common/Struct.h>
#include <vector>
#include <string>
#include <windows.h>

struct FaceData {
    std::string name;
    std::vector<float> features;
};

int main() {
    try {
        // 1. 初始化人脸检测器
        seeta::ModelSetting detector_setting("models/face_detector.csta", seeta::ModelSetting::CPU, 0);
        seeta::FaceDetector detector(detector_setting);
        detector.set(seeta::FaceDetector::PROPERTY_MIN_FACE_SIZE, 20);
        detector.set(seeta::FaceDetector::PROPERTY_THRESHOLD, 0.9);

        // 2. 初始化关键点检测器(用于提取5个关键点)
        seeta::ModelSetting landmarker_setting("models/face_landmarker_pts5.csta", seeta::ModelSetting::CPU, 0);
        seeta::FaceLandmarker landmarker(landmarker_setting);

        // 3. 初始化人脸识别器
        seeta::ModelSetting rec_setting("models/face_recognizer.csta", seeta::ModelSetting::CPU, 0);
        seeta::FaceRecognizer recognizer(rec_setting);

        std::cout << "初始化成功!" << std::endl;

        // 4. 加载人脸库
        std::vector<FaceData> face_database;
        std::string face_dir = "E:/faces/*.*";

        std::cout << "正在加载人脸库..." << std::endl;

        WIN32_FIND_DATA findData;
        HANDLE hFind = FindFirstFile(face_dir.c_str(), &findData);

        if (hFind != INVALID_HANDLE_VALUE) {
            do {
                if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;

                std::string filename = findData.cFileName;
                std::string ext = filename.substr(filename.find_last_of(".") + 1);

                if (ext == "jpg" || ext == "png" || ext == "jpeg" || ext == "bmp") {
                    std::string fullpath = "E:/faces/" + filename;
                    std::string name = filename.substr(0, filename.find_last_of("."));

                    cv::Mat img = cv::imread(fullpath);
                    if (img.empty()) continue;

                    SeetaImageData simg;
                    simg.data = img.data;
                    simg.width = img.cols;
                    simg.height = img.rows;
                    simg.channels = img.channels();

                    auto faces = detector.detect(simg);
                    if (faces.size > 0) {
                        // 获取关键点
                        std::vector<SeetaPointF> points(5);
                        landmarker.mark(simg, faces.data[0].pos, points.data());

                        // 提取特征
                        float features[1024];
                        recognizer.Extract(simg, points.data(), features);

                        FaceData fd;
                        fd.name = name;
                        fd.features.assign(features, features + 1024);
                        face_database.push_back(fd);

                        std::cout << "已加载: " << name << std::endl;
                    }
                }
            } while (FindNextFile(hFind, &findData) != 0);

            FindClose(hFind);
        }

        std::cout << "人脸库加载完成,共 " << face_database.size() << " 人" << std::endl;

        // 5. 打开摄像头
        cv::VideoCapture cap(0);
        if (!cap.isOpened()) {
            std::cerr << "无法打开摄像头!" << std::endl;
            return -1;
        }

        std::cout << "\n摄像头已打开,开始识别..." << std::endl;
        std::cout << "按 ESC 键退出" << std::endl;

        cv::Mat frame;
        while (true) {
            cap >> frame;
            if (frame.empty()) continue;

            SeetaImageData simg;
            simg.data = frame.data;
            simg.width = frame.cols;
            simg.height = frame.rows;
            simg.channels = frame.channels();

            auto faces = detector.detect(simg);

            for (int i = 0; i < faces.size; ++i) {
                auto& face = faces.data[i];

                // 绘制人脸框
                cv::Rect rect(face.pos.x, face.pos.y, face.pos.width, face.pos.height);

                // 获取关键点
                std::vector<SeetaPointF> points(5);
                landmarker.mark(simg, face.pos, points.data());

                // 提取特征
                float features[1024];
                recognizer.Extract(simg, points.data(), features);
                std::vector<float> current_feat(features, features + 1024);

                // 识别
                std::string recognized_name = "未知";
                float max_similarity = 0.0f;

                for (const auto& db_face : face_database) {
                    float sim = recognizer.CalculateSimilarity(
                        db_face.features.data(), current_feat.data());

                    if (sim > max_similarity && sim > 0.6f) {
                        max_similarity = sim;
                        recognized_name = db_face.name;
                    }
                }

                // 绘制人脸框
                cv::rectangle(frame, rect, cv::Scalar(0, 255, 0), 2);

                // 显示姓名
                cv::Scalar color = (recognized_name == "未知") ? cv::Scalar(0, 0, 255) : cv::Scalar(0, 255, 0);
                cv::putText(frame, recognized_name,
                    cv::Point(rect.x, rect.y - 10),
                    cv::FONT_HERSHEY_SIMPLEX, 0.8, color, 2);

                // 显示相似度
                if (max_similarity > 0.6f) {
                    char sim_text[32];
                    sprintf(sim_text, "%.2f", max_similarity);
                    cv::putText(frame, sim_text,
                        cv::Point(rect.x, rect.y + rect.height + 20),
                        cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(255, 255, 0), 1);
                }

                // 绘制关键点
                for (int j = 0; j < 5; j++) {
                    cv::circle(frame,
                        cv::Point(points[j].x, points[j].y),
                        2, cv::Scalar(0, 0, 255), -1);
                }
            }

            // 显示人脸数量
            char face_count[64];
            sprintf(face_count, "Faces: %d", faces.size);
            cv::putText(frame, face_count,
                cv::Point(10, 30),
                cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(255, 0, 0), 2);

            cv::imshow("Face Recognition", frame);

            if (cv::waitKey(1) == 27) break;
        }

    }
    catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << std::endl;
        return -1;
    }

    cv::destroyAllWindows();
    return 0;
}
posted @ 2026-03-09 17:08  Tlink  阅读(3)  评论(0)    收藏  举报