首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

OnnxRuntime部署LivePortrait实现快速、高质量的人像驱动视频生成

  • 25-02-19 03:41
  • 3794
  • 12357
blog.csdn.net

目录

说明

效果

代码


说明

官网地址:https://github.com/KwaiVGI/LivePortrait

代码地址:https://github.com/hpc203/liveportrait-onnxrun

模型下载:onnx文件在百度云盘,链接: https://pan.baidu.com/s/13wjBFRHIIyCyBsgnBOKqsw 提取码: si95

效果

LivePortrait实现快速、高质量的人像驱动视频生成

代码

main.cpp

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include "liveportrait.h"

using namespace cv;
using namespace std;


int main()
{
    LivePortraitPipeline mynet;
    
    string imgpath = "/home/wangbo/liveportrait-onnxrun/0.jpg";
    string videopath = "/home/wangbo/liveportrait-onnxrun/d0.mp4";
    
    mynet.execute(imgpath, videopath);

    return 0;
}

liveportrait.cpp

#include "liveportrait.h"
#include
#include

using namespace cv;
using namespace std;
using namespace Ort;

LivePortraitPipeline::LivePortraitPipeline()
{
    /// OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(sessionOptions, 0);   ///如果使用cuda加速,需要取消注释
    sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_BASIC);

    string model_path = "/home/wangbo/liveportrait-onnxrun/weights/appearance_feature_extractor.onnx";
    appearance_feature_extractor_ort_session = new Session(env, model_path.c_str(), sessionOptions);

    model_path = "/home/wangbo/liveportrait-onnxrun/weights/motion_extractor.onnx";
    motion_extractor_ort_session = new Session(env, model_path.c_str(), sessionOptions);

    model_path = "/home/wangbo/liveportrait-onnxrun/weights/warping_spade.onnx";
    warping_spade_ort_session = new Session(env, model_path.c_str(), sessionOptions);

    model_path = "/home/wangbo/liveportrait-onnxrun/weights/stitching.onnx";
    stitching_module_ort_session = new Session(env, model_path.c_str(), sessionOptions);

    model_path = "/home/wangbo/liveportrait-onnxrun/weights/landmark.onnx";
    /// std::wstring widestr = std::wstring(model_path.begin(), model_path.end());  windows写法
    /// landmark_runner_ort_session = new Session(env, widestr.c_str(), sessionOptions); windows写法
    landmark_runner_ort_session = new Session(env, model_path.c_str(), sessionOptions); linux写法
    /// 输出和输出节点名称在头文件里写死,在这里就不调用函数获取了

    this->face_analysis = std::make_shared("/home/wangbo/liveportrait-onnxrun/weights/retinaface_det_static.onnx", "/home/wangbo/liveportrait-onnxrun/weights/face_2dpose_106_static.onnx");

    this->mask_crop = imread("/home/wangbo/liveportrait-onnxrun/mask_template.png");
    cvtColor(this->mask_crop, this->mask_crop, COLOR_BGRA2BGR);
}

Mat LivePortraitPipeline::landmark_runner(const Mat &img, const float *lmk)
{
    std::map crop_dct;
    crop_image(img, lmk, 106, crop_dct, 224, 1.5, -0.1);

    std::vector input_img_shape = {1, 3, crop_dct["img_crop"].rows, crop_dct["img_crop"].cols};
    vector bgrChannels(3);
    split(crop_dct["img_crop"], bgrChannels);
    for (int c = 0; c < 3; c++)
    {
        bgrChannels[c].convertTo(bgrChannels[c], CV_32FC1, 1 / 255.0);
    }
    const int image_area = input_img_shape[2] * input_img_shape[3];
    this->landmark_runner_input_tensor.clear();
    this->landmark_runner_input_tensor.resize(input_img_shape[0] * input_img_shape[1] * image_area);
    size_t single_chn_size = image_area * sizeof(float);
    memcpy(this->landmark_runner_input_tensor.data(), (float *)bgrChannels[0].data, single_chn_size);
    memcpy(this->landmark_runner_input_tensor.data() + image_area, (float *)bgrChannels[1].data, single_chn_size);
    memcpy(this->landmark_runner_input_tensor.data() + image_area * 2, (float *)bgrChannels[2].data, single_chn_size);

    Value input_tensor = Value::CreateTensor(memory_info_handler, this->landmark_runner_input_tensor.data(), this->landmark_runner_input_tensor.size(), input_img_shape.data(), input_img_shape.size());
    vector ort_outputs = this->landmark_runner_ort_session->Run(runOptions, this->landmark_runner_input_names.data(), &input_tensor, 1, this->landmark_runner_output_names.data(), this->landmark_runner_output_names.size());
    float *out_pts = ort_outputs[2].GetTensorMutableData();
    const int num_pts = ort_outputs[2].GetTensorTypeAndShapeInfo().GetShape()[1] / 2;
    Mat lmk_mat(num_pts, 2, CV_32FC1);
    for (int i = 0; i < num_pts; i++)
    { btachsize=1,不考虑batchsize维度
        lmk_mat.at(i, 0) = out_pts[i * 2] * 224 * crop_dct["M_c2o"].at(0, 0) + out_pts[i * 2 + 1] * 224 * crop_dct["M_c2o"].at(0, 1) + crop_dct["M_c2o"].at(0, 2);
        lmk_mat.at(i, 1) = out_pts[i * 2] * 224 * crop_dct["M_c2o"].at(1, 0) + out_pts[i * 2 + 1] * 224 * crop_dct["M_c2o"].at(1, 1) + crop_dct["M_c2o"].at(1, 2);
    }
    return lmk_mat;
}

void LivePortraitPipeline::crop_src_image(const Mat &srcimg, std::map &crop_info)
{
    vector boxes = this->face_analysis->detect(srcimg);
    if (boxes.size() == 0)
    {
        cout << "No face detected in the source image." << endl;
        return;
    }
    else if (boxes.size() > 1)
    {
        cout << "More than one face detected in the image, only pick one face." << endl;
        return;
    }

    Bbox src_face = boxes[0];
    float *lmk = src_face.landmark_2d_106;

    crop_image(srcimg, lmk, 106, crop_info, 512, 2.3, -0.125);

    Mat lmk_crop = this->landmark_runner(srcimg, lmk);
    
    crop_info["lmk_crop"] = lmk_crop;
    Mat img_crop_256x256;
    resize(crop_info["img_crop"], img_crop_256x256, Size(256, 256), INTER_AREA);
    crop_info["img_crop_256x256"] = img_crop_256x256;
    crop_info["lmk_crop_256x256"] = crop_info["lmk_crop"] * 256 / 512;
}

void LivePortraitPipeline::get_kp_info(vector x, vector shape, std::map &kp_info)
{
    Value input_tensor = Value::CreateTensor(memory_info_handler, x.data(), x.size(), shape.data(), shape.size());
    vector ort_outputs = this->motion_extractor_ort_session->Run(runOptions, this->motion_extractor_input_names.data(), &input_tensor, 1, this->motion_extractor_output_names.data(), this->motion_extractor_output_names.size());
    pitch, yaw, roll, t, exp, scale, kp
    float *pitch = ort_outputs[0].GetTensorMutableData();
    float *yaw = ort_outputs[1].GetTensorMutableData();
    float *roll = ort_outputs[2].GetTensorMutableData();
    float *t = ort_outputs[3].GetTensorMutableData();
    float *exp = ort_outputs[4].GetTensorMutableData();
    float *scale = ort_outputs[5].GetTensorMutableData();
    float *kp = ort_outputs[6].GetTensorMutableData();

    vector pred;
    softmax(pitch, this->motion_extractor_output_shape[0], pred);
    const int bs = this->motion_extractor_output_shape[0][0];  batchsize=1,不考虑多图片输入
    const int len = 66; 66
    float sum = 0;
    for (int i = 0; i < len; i++)
    {
        sum += (i * pred[i]);
    }
    float degree = sum * 3 - 97.5;
    kp_info["pitch"] = (Mat_(1, 1) << degree);

    softmax(yaw, this->motion_extractor_output_shape[1], pred);
    sum = 0;
    for (int i = 0; i < len; i++)
    {
        sum += (i * pred[i]);
    }
    degree = sum * 3 - 97.5;
    kp_info["yaw"] = (Mat_(1, 1) << degree);

    softmax(roll, this->motion_extractor_output_shape[2], pred);
    sum = 0;
    for (int i = 0; i < len; i++)
    {
        sum += (i * pred[i]);
    }
    degree = sum * 3 - 97.5;
    kp_info["roll"] = (Mat_(1, 1) << degree);

    kp_info["t"] = Mat(1, 3, CV_32FC1, t);
    vector sizes = {1, 21, 3};   由于在c++的opencv里不支持3维Mat的矩阵乘法,此处不考虑batchsize维度
    vector sizes = {21, 3};
    kp_info["exp"] = Mat(sizes, CV_32FC1, exp);
    kp_info["scale"] = Mat(1, 1, CV_32FC1, scale);
    kp_info["kp"] = Mat(sizes, CV_32FC1, kp);
}

void LivePortraitPipeline::extract_feature_3d(vector x, vector shape, vector &f_s)
{
    Value input_tensor = Value::CreateTensor(memory_info_handler, x.data(), x.size(), shape.data(), shape.size());
    vector ort_outputs = this->appearance_feature_extractor_ort_session->Run(runOptions, this->appearance_feature_extractor_input_names.data(), &input_tensor, 1, this->appearance_feature_extractor_output_names.data(), this->appearance_feature_extractor_output_names.size());
    int numel = ort_outputs[0].GetTensorTypeAndShapeInfo().GetElementCount();
    float *out = ort_outputs[0].GetTensorMutableData();

    f_s.clear();
    f_s.resize(numel);
    memcpy(f_s.data(), out, numel * sizeof(float));
}

void LivePortraitPipeline::stitching(const Mat &kp_source, Mat &kp_driving_new)
{
    不考虑batchsize维度
    const int num_kp = kp_source.size[0];
    const int numel = kp_source.total();

    const int len = std::accumulate(this->stitching_module_input_shape.begin(), this->stitching_module_input_shape.end(), 1, std::multiplies());
    vector feat(len);
    memcpy(feat.data(), (float *)kp_source.data, numel * sizeof(float));
    memcpy(feat.data() + numel, (float *)kp_driving_new.data, (len - numel) * sizeof(float));

    Value input_tensor = Value::CreateTensor(memory_info_handler, feat.data(), feat.size(), this->stitching_module_input_shape.data(), this->stitching_module_input_shape.size());
    vector ort_outputs = this->stitching_module_ort_session->Run(runOptions, this->stitching_module_input_names.data(), &input_tensor, 1, this->stitching_module_output_names.data(), this->stitching_module_output_names.size());
    float *delta = ort_outputs[0].GetTensorMutableData();
    const float delta_tx_ty[2] = {delta[num_kp * 3], delta[num_kp * 3 + 1]};
    for (int i = 0; i < num_kp; i++)
    {
        kp_driving_new.at(i, 0) += delta[i * 3];
        kp_driving_new.at(i, 1) += delta[i * 3 + 1];
        kp_driving_new.at(i, 2) += delta[i * 3 + 2];

        kp_driving_new.at(i, 0) += delta_tx_ty[0];
        kp_driving_new.at(i, 1) += delta_tx_ty[1];
    }
}

Mat LivePortraitPipeline::warping_spade(vector feature_3d, const Mat &kp_source, const Mat &kp_driving)
{
    vector inputTensors;
    inputTensors.emplace_back(Ort::Value::CreateTensor(memory_info_handler, feature_3d.data(), feature_3d.size(), this->warping_spade_input_shape[0].data(), this->warping_spade_input_shape[0].size()));
    inputTensors.emplace_back(Ort::Value::CreateTensor(memory_info_handler, (float *)kp_driving.data, kp_driving.total(), this->warping_spade_input_shape[1].data(), this->warping_spade_input_shape[1].size()));
    inputTensors.emplace_back(Ort::Value::CreateTensor(memory_info_handler, (float *)kp_source.data, kp_source.total(), this->warping_spade_input_shape[2].data(), this->warping_spade_input_shape[2].size()));
    
    vector ort_outputs = this->warping_spade_ort_session->Run(runOptions, this->warping_spade_input_names.data(), inputTensors.data(), inputTensors.size(), this->warping_spade_output_names.data(), this->warping_spade_output_names.size());
    float *out = ort_outputs[0].GetTensorMutableData();
    Mat out_mat = Mat(this->warping_spade_output_shape, CV_32FC1, out);
    return out_mat;
}

Mat LivePortraitPipeline::predict(const int frame_id, std::map x_s_info, const Mat &R_s, vector f_s, const Mat &x_s, const Mat &frame)
{
    Mat lmk;
    if (frame_id > 0)
    {
        lmk = this->landmark_runner(frame, (float*)this->pred_info_lmk.data);
    }
    else
    {
        vector boxes = this->face_analysis->detect(frame);
        if (boxes.size() == 0)
        {
            cout << "No face detected in the frame." << endl;
            exit(-1);
        }
        else if (boxes.size() > 1)
        {
            cout << "More than one face detected in the driving frame, only pick one face." << endl;
            exit(-1);
        }
        Bbox src_face = boxes[0];
        lmk = this->landmark_runner(frame, src_face.landmark_2d_106);
    }
    lmk.copyTo(this->pred_info_lmk);

    float c_d_eyes[2] = {calculate_distance_ratio(lmk, 6, 18, 0, 12), calculate_distance_ratio(lmk, 30, 42, 24, 36)};
    float c_d_lip = calculate_distance_ratio(lmk, 90, 102, 48, 66);

    Mat img;
    resize(frame, img, Size(256, 256));
    vector I_d;
    vector I_d_shape;
    preprocess(img, I_d, I_d_shape);

    std::map x_d_info;
    this->get_kp_info(I_d, I_d_shape, x_d_info);
    Mat R_d = get_rotation_matrix(x_d_info["pitch"], x_d_info["yaw"], x_d_info["roll"]);
    x_d_info["R_d"] = R_d;
    x_d_info.erase("pitch");
    x_d_info.erase("yaw");
    x_d_info.erase("roll");
    x_d_info.erase("kp");

    if (frame_id == 0)
    {
        this->pred_info_x_d_0_info["scale"] = x_d_info["scale"].clone();   ///也可以定义结构体的方式打包参数
        this->pred_info_x_d_0_info["R_d"] = R_d.clone();
        this->pred_info_x_d_0_info["exp"] = x_d_info["exp"].clone();
        this->pred_info_x_d_0_info["t"] = x_d_info["t"].clone();
    }

    Mat R_new = (R_d * this->pred_info_x_d_0_info["R_d"].t()) * R_s;
    Mat delta_new = x_s_info["exp"] + (x_d_info["exp"] - this->pred_info_x_d_0_info["exp"]);
    Mat scale_new = x_s_info["scale"].mul(x_d_info["scale"] / this->pred_info_x_d_0_info["scale"]); /// scale是1x1矩阵,也就是单个数值
    Mat t_new = x_s_info["t"] + (x_d_info["t"] - this->pred_info_x_d_0_info["t"]);
    
    t_new.at(0, 2) = 0;
    Mat temp = repeat(t_new, 21, 1);
    Mat x_d_new = scale_new.at(0, 0) * (x_s_info["kp"] * R_new + delta_new) + temp;
    
    this->stitching(x_s, x_d_new);
    
    Mat out = this->warping_spade(f_s, x_s, x_d_new);   形状是[1,3,512,512]
    const int image_erea = out.size[2] * out.size[3];
    float *pdata = (float *)out.data;
    Mat rmat = Mat(out.size[2], out.size[3], CV_32FC1, pdata);
    Mat gmat = Mat(out.size[2], out.size[3], CV_32FC1, pdata + image_erea);
    Mat bmat = Mat(out.size[2], out.size[3], CV_32FC1, pdata + image_erea * 2);
    rmat.setTo(0, rmat < 0);
    rmat.setTo(1, rmat > 1);
    gmat.setTo(0, gmat < 0);
    gmat.setTo(1, gmat > 1);
    bmat.setTo(0, bmat < 0);
    bmat.setTo(1, bmat > 1);
    vector channel_mats(3);
    channel_mats[0] = rmat;
    channel_mats[1] = gmat;
    channel_mats[2] = bmat;
    Mat I_p;
    merge(channel_mats, I_p);
    I_p *= 255;
    I_p.convertTo(I_p, CV_8UC3);
    return I_p;
}

int LivePortraitPipeline::execute(string imgpath, string videopath)
{
    Mat srcimg = imread(imgpath);
    if (srcimg.empty())
    {
        cout << "opencv读取图片为空, 请检查输入图片的路径" << endl;
        return -1;
    }

    Mat img;
    cvtColor(srcimg, img, COLOR_BGRA2BGR);
    cvtColor(img, img, COLOR_BGR2RGB);
    Mat src_img = src_preprocess(img);
    std::map crop_info;
    crop_src_image(src_img, crop_info);

    Mat img_crop_256x256 = crop_info["img_crop_256x256"];
    vector I_s;
    vector I_s_shape;
    preprocess(img_crop_256x256, I_s, I_s_shape);

    std::map x_s_info;
    this->get_kp_info(I_s, I_s_shape, x_s_info);
    Mat R_s = get_rotation_matrix(x_s_info["pitch"], x_s_info["yaw"], x_s_info["roll"]);  返回结果已验证通过

    vector f_s;
    this->extract_feature_3d(I_s, I_s_shape, f_s);
    Mat x_s = transform_keypoint(x_s_info);

    cv::VideoCapture capture(videopath);
    if (!capture.isOpened())
    {
        cout << "VideoCapture,open video file failed, " << videopath << endl;
        return -1;
    }
    const int fps = capture.get(cv::CAP_PROP_FPS);
    const int video_length = capture.get(cv::CAP_PROP_FRAME_COUNT);
    cout<<"video total have "<     int f_h = src_img.rows;
    int f_w = src_img.cols;
    if (this->flg_composite)
    {
        f_h = 512;
        f_w = 512 * 3;
    }

    prepare for pasteback
    Mat mask_ori = prepare_paste_back(this->mask_crop, crop_info["M_c2o"], Size(src_img.cols, src_img.rows));

    VideoWriter video_writer;
    video_writer.open("output.mp4", cv::VideoWriter::fourcc('m', 'p', '4', 'v'), fps, Size(f_w, f_h));
    Mat frame;
    int frame_id = 0;
    while (capture.read(frame))
    {
        if (frame.empty())
        {
            break;
        }

        Mat img_rgb;
        cvtColor(frame, img_rgb, COLOR_BGR2RGB);
        auto a = std::chrono::high_resolution_clock::now();
        Mat I_p = this->predict(frame_id, x_s_info, R_s, f_s, x_s, img_rgb);
        auto b = std::chrono::high_resolution_clock::now();
        std::chrono::duration c = b - a;
        cout<<"frame_id="<         
        frame_id += 1;
        Mat driving_img;
        if (this->flg_composite)
        {
            concat_frame(img_rgb, img_crop_256x256, I_p, driving_img);
        }
        else
        {
            paste_back(I_p, crop_info["M_c2o"], src_img, mask_ori, driving_img);
        }
        cvtColor(driving_img, driving_img, COLOR_RGB2BGR);
        video_writer.write(driving_img);
    }
    video_writer.release();
    capture.release();
    ///destroyAllWindows();
    return 0;
}

  1. #include "liveportrait.h"
  2. #include <opencv2/highgui.hpp>
  3. #include <numeric>
  4. using namespace cv;
  5. using namespace std;
  6. using namespace Ort;
  7. LivePortraitPipeline::LivePortraitPipeline()
  8. {
  9. /// OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(sessionOptions, 0); ///如果使用cuda加速,需要取消注释
  10. sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_BASIC);
  11. string model_path = "/home/wangbo/liveportrait-onnxrun/weights/appearance_feature_extractor.onnx";
  12. appearance_feature_extractor_ort_session = new Session(env, model_path.c_str(), sessionOptions);
  13. model_path = "/home/wangbo/liveportrait-onnxrun/weights/motion_extractor.onnx";
  14. motion_extractor_ort_session = new Session(env, model_path.c_str(), sessionOptions);
  15. model_path = "/home/wangbo/liveportrait-onnxrun/weights/warping_spade.onnx";
  16. warping_spade_ort_session = new Session(env, model_path.c_str(), sessionOptions);
  17. model_path = "/home/wangbo/liveportrait-onnxrun/weights/stitching.onnx";
  18. stitching_module_ort_session = new Session(env, model_path.c_str(), sessionOptions);
  19. model_path = "/home/wangbo/liveportrait-onnxrun/weights/landmark.onnx";
  20. /// std::wstring widestr = std::wstring(model_path.begin(), model_path.end()); windows写法
  21. /// landmark_runner_ort_session = new Session(env, widestr.c_str(), sessionOptions); windows写法
  22. landmark_runner_ort_session = new Session(env, model_path.c_str(), sessionOptions); linux写法
  23. /// 输出和输出节点名称在头文件里写死,在这里就不调用函数获取了
  24. this->face_analysis = std::make_shared<FaceAnalysis>("/home/wangbo/liveportrait-onnxrun/weights/retinaface_det_static.onnx", "/home/wangbo/liveportrait-onnxrun/weights/face_2dpose_106_static.onnx");
  25. this->mask_crop = imread("/home/wangbo/liveportrait-onnxrun/mask_template.png");
  26. cvtColor(this->mask_crop, this->mask_crop, COLOR_BGRA2BGR);
  27. }
  28. Mat LivePortraitPipeline::landmark_runner(const Mat &img, const float *lmk)
  29. {
  30. std::map<string, Mat> crop_dct;
  31. crop_image(img, lmk, 106, crop_dct, 224, 1.5, -0.1);
  32. std::vector<int64_t> input_img_shape = {1, 3, crop_dct["img_crop"].rows, crop_dct["img_crop"].cols};
  33. vector<cv::Mat> bgrChannels(3);
  34. split(crop_dct["img_crop"], bgrChannels);
  35. for (int c = 0; c < 3; c++)
  36. {
  37. bgrChannels[c].convertTo(bgrChannels[c], CV_32FC1, 1 / 255.0);
  38. }
  39. const int image_area = input_img_shape[2] * input_img_shape[3];
  40. this->landmark_runner_input_tensor.clear();
  41. this->landmark_runner_input_tensor.resize(input_img_shape[0] * input_img_shape[1] * image_area);
  42. size_t single_chn_size = image_area * sizeof(float);
  43. memcpy(this->landmark_runner_input_tensor.data(), (float *)bgrChannels[0].data, single_chn_size);
  44. memcpy(this->landmark_runner_input_tensor.data() + image_area, (float *)bgrChannels[1].data, single_chn_size);
  45. memcpy(this->landmark_runner_input_tensor.data() + image_area * 2, (float *)bgrChannels[2].data, single_chn_size);
  46. Value input_tensor = Value::CreateTensor<float>(memory_info_handler, this->landmark_runner_input_tensor.data(), this->landmark_runner_input_tensor.size(), input_img_shape.data(), input_img_shape.size());
  47. vector<Value> ort_outputs = this->landmark_runner_ort_session->Run(runOptions, this->landmark_runner_input_names.data(), &input_tensor, 1, this->landmark_runner_output_names.data(), this->landmark_runner_output_names.size());
  48. float *out_pts = ort_outputs[2].GetTensorMutableData<float>();
  49. const int num_pts = ort_outputs[2].GetTensorTypeAndShapeInfo().GetShape()[1] / 2;
  50. Mat lmk_mat(num_pts, 2, CV_32FC1);
  51. for (int i = 0; i < num_pts; i++)
  52. { btachsize=1,不考虑batchsize维度
  53. lmk_mat.at<float>(i, 0) = out_pts[i * 2] * 224 * crop_dct["M_c2o"].at<float>(0, 0) + out_pts[i * 2 + 1] * 224 * crop_dct["M_c2o"].at<float>(0, 1) + crop_dct["M_c2o"].at<float>(0, 2);
  54. lmk_mat.at<float>(i, 1) = out_pts[i * 2] * 224 * crop_dct["M_c2o"].at<float>(1, 0) + out_pts[i * 2 + 1] * 224 * crop_dct["M_c2o"].at<float>(1, 1) + crop_dct["M_c2o"].at<float>(1, 2);
  55. }
  56. return lmk_mat;
  57. }
  58. void LivePortraitPipeline::crop_src_image(const Mat &srcimg, std::map<string, Mat> &crop_info)
  59. {
  60. vector<Bbox> boxes = this->face_analysis->detect(srcimg);
  61. if (boxes.size() == 0)
  62. {
  63. cout << "No face detected in the source image." << endl;
  64. return;
  65. }
  66. else if (boxes.size() > 1)
  67. {
  68. cout << "More than one face detected in the image, only pick one face." << endl;
  69. return;
  70. }
  71. Bbox src_face = boxes[0];
  72. float *lmk = src_face.landmark_2d_106;
  73. crop_image(srcimg, lmk, 106, crop_info, 512, 2.3, -0.125);
  74. Mat lmk_crop = this->landmark_runner(srcimg, lmk);
  75. crop_info["lmk_crop"] = lmk_crop;
  76. Mat img_crop_256x256;
  77. resize(crop_info["img_crop"], img_crop_256x256, Size(256, 256), INTER_AREA);
  78. crop_info["img_crop_256x256"] = img_crop_256x256;
  79. crop_info["lmk_crop_256x256"] = crop_info["lmk_crop"] * 256 / 512;
  80. }
  81. void LivePortraitPipeline::get_kp_info(vector<float> x, vector<int64_t> shape, std::map<string, Mat> &kp_info)
  82. {
  83. Value input_tensor = Value::CreateTensor<float>(memory_info_handler, x.data(), x.size(), shape.data(), shape.size());
  84. vector<Value> ort_outputs = this->motion_extractor_ort_session->Run(runOptions, this->motion_extractor_input_names.data(), &input_tensor, 1, this->motion_extractor_output_names.data(), this->motion_extractor_output_names.size());
  85. pitch, yaw, roll, t, exp, scale, kp
  86. float *pitch = ort_outputs[0].GetTensorMutableData<float>();
  87. float *yaw = ort_outputs[1].GetTensorMutableData<float>();
  88. float *roll = ort_outputs[2].GetTensorMutableData<float>();
  89. float *t = ort_outputs[3].GetTensorMutableData<float>();
  90. float *exp = ort_outputs[4].GetTensorMutableData<float>();
  91. float *scale = ort_outputs[5].GetTensorMutableData<float>();
  92. float *kp = ort_outputs[6].GetTensorMutableData<float>();
  93. vector<float> pred;
  94. softmax(pitch, this->motion_extractor_output_shape[0], pred);
  95. const int bs = this->motion_extractor_output_shape[0][0]; batchsize=1,不考虑多图片输入
  96. const int len = 66; 66
  97. float sum = 0;
  98. for (int i = 0; i < len; i++)
  99. {
  100. sum += (i * pred[i]);
  101. }
  102. float degree = sum * 3 - 97.5;
  103. kp_info["pitch"] = (Mat_<float>(1, 1) << degree);
  104. softmax(yaw, this->motion_extractor_output_shape[1], pred);
  105. sum = 0;
  106. for (int i = 0; i < len; i++)
  107. {
  108. sum += (i * pred[i]);
  109. }
  110. degree = sum * 3 - 97.5;
  111. kp_info["yaw"] = (Mat_<float>(1, 1) << degree);
  112. softmax(roll, this->motion_extractor_output_shape[2], pred);
  113. sum = 0;
  114. for (int i = 0; i < len; i++)
  115. {
  116. sum += (i * pred[i]);
  117. }
  118. degree = sum * 3 - 97.5;
  119. kp_info["roll"] = (Mat_<float>(1, 1) << degree);
  120. kp_info["t"] = Mat(1, 3, CV_32FC1, t);
  121. vector<int> sizes = {1, 21, 3}; 由于在c++的opencv里不支持3维Mat的矩阵乘法,此处不考虑batchsize维度
  122. vector<int> sizes = {21, 3};
  123. kp_info["exp"] = Mat(sizes, CV_32FC1, exp);
  124. kp_info["scale"] = Mat(1, 1, CV_32FC1, scale);
  125. kp_info["kp"] = Mat(sizes, CV_32FC1, kp);
  126. }
  127. void LivePortraitPipeline::extract_feature_3d(vector<float> x, vector<int64_t> shape, vector<float> &f_s)
  128. {
  129. Value input_tensor = Value::CreateTensor<float>(memory_info_handler, x.data(), x.size(), shape.data(), shape.size());
  130. vector<Value> ort_outputs = this->appearance_feature_extractor_ort_session->Run(runOptions, this->appearance_feature_extractor_input_names.data(), &input_tensor, 1, this->appearance_feature_extractor_output_names.data(), this->appearance_feature_extractor_output_names.size());
  131. int numel = ort_outputs[0].GetTensorTypeAndShapeInfo().GetElementCount();
  132. float *out = ort_outputs[0].GetTensorMutableData<float>();
  133. f_s.clear();
  134. f_s.resize(numel);
  135. memcpy(f_s.data(), out, numel * sizeof(float));
  136. }
  137. void LivePortraitPipeline::stitching(const Mat &kp_source, Mat &kp_driving_new)
  138. {
  139. 不考虑batchsize维度
  140. const int num_kp = kp_source.size[0];
  141. const int numel = kp_source.total();
  142. const int len = std::accumulate(this->stitching_module_input_shape.begin(), this->stitching_module_input_shape.end(), 1, std::multiplies<int64_t>());
  143. vector<float> feat(len);
  144. memcpy(feat.data(), (float *)kp_source.data, numel * sizeof(float));
  145. memcpy(feat.data() + numel, (float *)kp_driving_new.data, (len - numel) * sizeof(float));
  146. Value input_tensor = Value::CreateTensor<float>(memory_info_handler, feat.data(), feat.size(), this->stitching_module_input_shape.data(), this->stitching_module_input_shape.size());
  147. vector<Value> ort_outputs = this->stitching_module_ort_session->Run(runOptions, this->stitching_module_input_names.data(), &input_tensor, 1, this->stitching_module_output_names.data(), this->stitching_module_output_names.size());
  148. float *delta = ort_outputs[0].GetTensorMutableData<float>();
  149. const float delta_tx_ty[2] = {delta[num_kp * 3], delta[num_kp * 3 + 1]};
  150. for (int i = 0; i < num_kp; i++)
  151. {
  152. kp_driving_new.at<float>(i, 0) += delta[i * 3];
  153. kp_driving_new.at<float>(i, 1) += delta[i * 3 + 1];
  154. kp_driving_new.at<float>(i, 2) += delta[i * 3 + 2];
  155. kp_driving_new.at<float>(i, 0) += delta_tx_ty[0];
  156. kp_driving_new.at<float>(i, 1) += delta_tx_ty[1];
  157. }
  158. }
  159. Mat LivePortraitPipeline::warping_spade(vector<float> feature_3d, const Mat &kp_source, const Mat &kp_driving)
  160. {
  161. vector<Ort::Value> inputTensors;
  162. inputTensors.emplace_back(Ort::Value::CreateTensor<float>(memory_info_handler, feature_3d.data(), feature_3d.size(), this->warping_spade_input_shape[0].data(), this->warping_spade_input_shape[0].size()));
  163. inputTensors.emplace_back(Ort::Value::CreateTensor<float>(memory_info_handler, (float *)kp_driving.data, kp_driving.total(), this->warping_spade_input_shape[1].data(), this->warping_spade_input_shape[1].size()));
  164. inputTensors.emplace_back(Ort::Value::CreateTensor<float>(memory_info_handler, (float *)kp_source.data, kp_source.total(), this->warping_spade_input_shape[2].data(), this->warping_spade_input_shape[2].size()));
  165. vector<Value> ort_outputs = this->warping_spade_ort_session->Run(runOptions, this->warping_spade_input_names.data(), inputTensors.data(), inputTensors.size(), this->warping_spade_output_names.data(), this->warping_spade_output_names.size());
  166. float *out = ort_outputs[0].GetTensorMutableData<float>();
  167. Mat out_mat = Mat(this->warping_spade_output_shape, CV_32FC1, out);
  168. return out_mat;
  169. }
  170. Mat LivePortraitPipeline::predict(const int frame_id, std::map<string, Mat> x_s_info, const Mat &R_s, vector<float> f_s, const Mat &x_s, const Mat &frame)
  171. {
  172. Mat lmk;
  173. if (frame_id > 0)
  174. {
  175. lmk = this->landmark_runner(frame, (float*)this->pred_info_lmk.data);
  176. }
  177. else
  178. {
  179. vector<Bbox> boxes = this->face_analysis->detect(frame);
  180. if (boxes.size() == 0)
  181. {
  182. cout << "No face detected in the frame." << endl;
  183. exit(-1);
  184. }
  185. else if (boxes.size() > 1)
  186. {
  187. cout << "More than one face detected in the driving frame, only pick one face." << endl;
  188. exit(-1);
  189. }
  190. Bbox src_face = boxes[0];
  191. lmk = this->landmark_runner(frame, src_face.landmark_2d_106);
  192. }
  193. lmk.copyTo(this->pred_info_lmk);
  194. float c_d_eyes[2] = {calculate_distance_ratio(lmk, 6, 18, 0, 12), calculate_distance_ratio(lmk, 30, 42, 24, 36)};
  195. float c_d_lip = calculate_distance_ratio(lmk, 90, 102, 48, 66);
  196. Mat img;
  197. resize(frame, img, Size(256, 256));
  198. vector<float> I_d;
  199. vector<int64_t> I_d_shape;
  200. preprocess(img, I_d, I_d_shape);
  201. std::map<string, Mat> x_d_info;
  202. this->get_kp_info(I_d, I_d_shape, x_d_info);
  203. Mat R_d = get_rotation_matrix(x_d_info["pitch"], x_d_info["yaw"], x_d_info["roll"]);
  204. x_d_info["R_d"] = R_d;
  205. x_d_info.erase("pitch");
  206. x_d_info.erase("yaw");
  207. x_d_info.erase("roll");
  208. x_d_info.erase("kp");
  209. if (frame_id == 0)
  210. {
  211. this->pred_info_x_d_0_info["scale"] = x_d_info["scale"].clone(); ///也可以定义结构体的方式打包参数
  212. this->pred_info_x_d_0_info["R_d"] = R_d.clone();
  213. this->pred_info_x_d_0_info["exp"] = x_d_info["exp"].clone();
  214. this->pred_info_x_d_0_info["t"] = x_d_info["t"].clone();
  215. }
  216. Mat R_new = (R_d * this->pred_info_x_d_0_info["R_d"].t()) * R_s;
  217. Mat delta_new = x_s_info["exp"] + (x_d_info["exp"] - this->pred_info_x_d_0_info["exp"]);
  218. Mat scale_new = x_s_info["scale"].mul(x_d_info["scale"] / this->pred_info_x_d_0_info["scale"]); /// scale是1x1矩阵,也就是单个数值
  219. Mat t_new = x_s_info["t"] + (x_d_info["t"] - this->pred_info_x_d_0_info["t"]);
  220. t_new.at<float>(0, 2) = 0;
  221. Mat temp = repeat(t_new, 21, 1);
  222. Mat x_d_new = scale_new.at<float>(0, 0) * (x_s_info["kp"] * R_new + delta_new) + temp;
  223. this->stitching(x_s, x_d_new);
  224. Mat out = this->warping_spade(f_s, x_s, x_d_new); 形状是[1,3,512,512]
  225. const int image_erea = out.size[2] * out.size[3];
  226. float *pdata = (float *)out.data;
  227. Mat rmat = Mat(out.size[2], out.size[3], CV_32FC1, pdata);
  228. Mat gmat = Mat(out.size[2], out.size[3], CV_32FC1, pdata + image_erea);
  229. Mat bmat = Mat(out.size[2], out.size[3], CV_32FC1, pdata + image_erea * 2);
  230. rmat.setTo(0, rmat < 0);
  231. rmat.setTo(1, rmat > 1);
  232. gmat.setTo(0, gmat < 0);
  233. gmat.setTo(1, gmat > 1);
  234. bmat.setTo(0, bmat < 0);
  235. bmat.setTo(1, bmat > 1);
  236. vector<Mat> channel_mats(3);
  237. channel_mats[0] = rmat;
  238. channel_mats[1] = gmat;
  239. channel_mats[2] = bmat;
  240. Mat I_p;
  241. merge(channel_mats, I_p);
  242. I_p *= 255;
  243. I_p.convertTo(I_p, CV_8UC3);
  244. return I_p;
  245. }
  246. int LivePortraitPipeline::execute(string imgpath, string videopath)
  247. {
  248. Mat srcimg = imread(imgpath);
  249. if (srcimg.empty())
  250. {
  251. cout << "opencv读取图片为空, 请检查输入图片的路径" << endl;
  252. return -1;
  253. }
  254. Mat img;
  255. cvtColor(srcimg, img, COLOR_BGRA2BGR);
  256. cvtColor(img, img, COLOR_BGR2RGB);
  257. Mat src_img = src_preprocess(img);
  258. std::map<string, Mat> crop_info;
  259. crop_src_image(src_img, crop_info);
  260. Mat img_crop_256x256 = crop_info["img_crop_256x256"];
  261. vector<float> I_s;
  262. vector<int64_t> I_s_shape;
  263. preprocess(img_crop_256x256, I_s, I_s_shape);
  264. std::map<string, Mat> x_s_info;
  265. this->get_kp_info(I_s, I_s_shape, x_s_info);
  266. Mat R_s = get_rotation_matrix(x_s_info["pitch"], x_s_info["yaw"], x_s_info["roll"]); 返回结果已验证通过
  267. vector<float> f_s;
  268. this->extract_feature_3d(I_s, I_s_shape, f_s);
  269. Mat x_s = transform_keypoint(x_s_info);
  270. cv::VideoCapture capture(videopath);
  271. if (!capture.isOpened())
  272. {
  273. cout << "VideoCapture,open video file failed, " << videopath << endl;
  274. return -1;
  275. }
  276. const int fps = capture.get(cv::CAP_PROP_FPS);
  277. const int video_length = capture.get(cv::CAP_PROP_FRAME_COUNT);
  278. cout<<"video total have "<<video_length<<" frames"<<endl;
  279. int f_h = src_img.rows;
  280. int f_w = src_img.cols;
  281. if (this->flg_composite)
  282. {
  283. f_h = 512;
  284. f_w = 512 * 3;
  285. }
  286. prepare for pasteback
  287. Mat mask_ori = prepare_paste_back(this->mask_crop, crop_info["M_c2o"], Size(src_img.cols, src_img.rows));
  288. VideoWriter video_writer;
  289. video_writer.open("output.mp4", cv::VideoWriter::fourcc('m', 'p', '4', 'v'), fps, Size(f_w, f_h));
  290. Mat frame;
  291. int frame_id = 0;
  292. while (capture.read(frame))
  293. {
  294. if (frame.empty())
  295. {
  296. break;
  297. }
  298. Mat img_rgb;
  299. cvtColor(frame, img_rgb, COLOR_BGR2RGB);
  300. auto a = std::chrono::high_resolution_clock::now();
  301. Mat I_p = this->predict(frame_id, x_s_info, R_s, f_s, x_s, img_rgb);
  302. auto b = std::chrono::high_resolution_clock::now();
  303. std::chrono::duration<double> c = b - a;
  304. cout<<"frame_id="<<frame_id<<", predict waste time="<<to_string(c.count())<<" s"<<endl;
  305. frame_id += 1;
  306. Mat driving_img;
  307. if (this->flg_composite)
  308. {
  309. concat_frame(img_rgb, img_crop_256x256, I_p, driving_img);
  310. }
  311. else
  312. {
  313. paste_back(I_p, crop_info["M_c2o"], src_img, mask_ori, driving_img);
  314. }
  315. cvtColor(driving_img, driving_img, COLOR_RGB2BGR);
  316. video_writer.write(driving_img);
  317. }
  318. video_writer.release();
  319. capture.release();
  320. ///destroyAllWindows();
  321. return 0;
  322. }

faceanalysis.cpp

  1. #include "faceanalysis.h"
  2. using namespace cv;
  3. using namespace std;
  4. using namespace Ort;
  5. FaceAnalysis::FaceAnalysis(string model_patha, string model_pathb)
  6. {
  7. /// OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(sessionOptions, 0); ///如果使用cuda加速,需要取消注释
  8. sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_BASIC);
  9. /// std::wstring widestr = std::wstring(model_patha.begin(), model_patha.end()); windows写法
  10. /// ort_session = new Session(env, widestr.c_str(), sessionOptions); windows写法
  11. det_face_ort_session = new Session(env, model_patha.c_str(), sessionOptions); linux写法
  12. size_t numInputNodes = det_face_ort_session->GetInputCount();
  13. size_t numOutputNodes = det_face_ort_session->GetOutputCount();
  14. AllocatorWithDefaultOptions allocator;
  15. for (int i = 0; i < numOutputNodes; i++)
  16. {
  17. Ort::TypeInfo output_type_info = det_face_ort_session->GetOutputTypeInfo(i);
  18. auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo();
  19. auto output_dims = output_tensor_info.GetShape();
  20. det_face_output_node_dims.push_back(output_dims);
  21. }
  22. /// std::wstring widestr = std::wstring(model_pathb.begin(), model_pathb.end()); windows写法
  23. /// ort_session = new Session(env, widestr.c_str(), sessionOptions); windows写法
  24. landmark_ort_session = new Session(env, model_pathb.c_str(), sessionOptions); linux写法
  25. numInputNodes = landmark_ort_session->GetInputCount();
  26. numOutputNodes = landmark_ort_session->GetOutputCount();
  27. Ort::TypeInfo input_type_info = landmark_ort_session->GetInputTypeInfo(0);
  28. auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo();
  29. auto input_dims = input_tensor_info.GetShape();
  30. this->landmark_input_height = input_dims[2];
  31. this->landmark_input_width = input_dims[3];
  32. this->landmark_input_tensor_shape = { 1, 3, this->landmark_input_height, this->landmark_input_width };
  33. Ort::TypeInfo output_type_info = landmark_ort_session->GetOutputTypeInfo(0);
  34. auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo();
  35. auto output_dims = output_tensor_info.GetShape();
  36. landmark_output_node_dims.push_back(output_dims);
  37. }
  38. void FaceAnalysis::preprocess(Mat srcimg)
  39. {
  40. const float im_ratio = float(srcimg.rows) / (float)srcimg.cols;
  41. int new_width = this->input_size;
  42. int new_height = int(new_width * im_ratio);
  43. if(im_ratio>1)
  44. {
  45. new_height = this->input_size;
  46. new_width = int(new_height / im_ratio);
  47. }
  48. this->det_scale = float(new_height) / (float)srcimg.rows;
  49. Mat resized_img;
  50. resize(srcimg, resized_img, Size(new_width, new_height));
  51. Mat det_img;
  52. copyMakeBorder(resized_img, det_img, 0, this->input_size - new_height, 0, this->input_size - new_width, BORDER_CONSTANT, 0);
  53. vector<cv::Mat> bgrChannels(3);
  54. split(det_img, bgrChannels);
  55. for (int c = 0; c < 3; c++)
  56. {
  57. bgrChannels[c].convertTo(bgrChannels[c], CV_32FC1, 1 / 128.0, -127.5 / 128.0);
  58. }
  59. const int image_area = this->input_size * this->input_size;
  60. this->input_image.resize(3 * image_area);
  61. size_t single_chn_size = image_area * sizeof(float);
  62. memcpy(this->input_image.data(), (float *)bgrChannels[0].data, single_chn_size);
  63. memcpy(this->input_image.data() + image_area, (float *)bgrChannels[1].data, single_chn_size);
  64. memcpy(this->input_image.data() + image_area * 2, (float *)bgrChannels[2].data, single_chn_size);
  65. }
  66. void FaceAnalysis::generate_proposal(const float* p_box, const float* p_scores, const float* p_kps, const int stride, vector<Bbox>& boxes)
  67. {
  68. const int feat_h = this->input_size / stride;
  69. const int feat_w = this->input_size / stride;
  70. const int num_anchors = 2;
  71. for (int i = 0; i < feat_h; i++)
  72. {
  73. for (int j = 0; j < feat_w; j++)
  74. {
  75. for(int n=0; n<num_anchors; n++)
  76. {
  77. const int index = i * feat_w*num_anchors + j*num_anchors+n;
  78. if(p_scores[index] >= this->det_thresh)
  79. {
  80. Bbox box;
  81. box.xmin = (j - p_box[index * 4]) * stride;
  82. box.ymin = (i - p_box[index * 4 + 1]) * stride;
  83. box.xmax = (j + p_box[index * 4 + 2]) * stride;
  84. box.ymax = (i + p_box[index * 4 + 3]) * stride;
  85. box.xmin /= this->det_scale;
  86. box.ymin /= this->det_scale;
  87. box.xmax /= this->det_scale;
  88. box.ymax /= this->det_scale;
  89. for(int k=0;k<5;k++)
  90. {
  91. float px = (j + p_kps[index * 10 + k * 2]) * stride;
  92. float py = (i + p_kps[index * 10 + k * 2 + 1]) * stride;
  93. px /= this->det_scale;
  94. py /= this->det_scale;
  95. box.kps[k * 2] = px;
  96. box.kps[k * 2 + 1] = py;
  97. }
  98. box.score = p_scores[index];
  99. boxes.emplace_back(box);
  100. }
  101. }
  102. }
  103. }
  104. }
  105. bool cmp(Bbox a, Bbox b)
  106. {
  107. float area_a = (a.xmax - a.xmin) * (a.ymax - a.ymin);
  108. float area_b = (b.xmax - b.xmin) * (b.ymax - b.ymin);
  109. return area_a > area_b;
  110. }
  111. vector<Bbox> FaceAnalysis::detect(const Mat& srcimg)
  112. {
  113. this->preprocess(srcimg);
  114. std::vector<int64_t> input_img_shape = {1, 3, this->input_size, this->input_size}; ///也可以写在构造函数里, det_face的输入是动态的
  115. Value input_tensor_ = Value::CreateTensor<float>(memory_info_handler, this->input_image.data(), this->input_image.size(), input_img_shape.data(), input_img_shape.size());
  116. vector<Value> det_face_ort_outputs = this->det_face_ort_session->Run(runOptions, this->det_face_input_names.data(), &input_tensor_, 1, this->det_face_output_names.data(), this->det_face_output_names.size());
  117. vector<Bbox> boxes;
  118. for(int i=0;i<3;i++)
  119. {
  120. float *p_scores = det_face_ort_outputs[i].GetTensorMutableData<float>();
  121. float *p_bbox = det_face_ort_outputs[i + this->fmc].GetTensorMutableData<float>();
  122. float *p_kps = det_face_ort_outputs[i + this->fmc*2].GetTensorMutableData<float>();
  123. this->generate_proposal(p_bbox, p_scores, p_kps, this->feat_stride_fpn[i], boxes);
  124. }
  125. nms_boxes(boxes, this->nms_thresh);
  126. for(int i=0;i<boxes.size();i++)
  127. {
  128. get_landmark
  129. float w = boxes[i].xmax - boxes[i].xmin;
  130. float h = boxes[i].ymax - boxes[i].ymin;
  131. float center[2] = {(boxes[i].xmin + boxes[i].xmax) * 0.5f, (boxes[i].ymin + boxes[i].ymax) * 0.5f};
  132. float rot = 0.f*PI/180.f;
  133. float scale_ratio = this->landmark_input_size / (max(w, h) * 1.5);
  134. face_align
  135. Mat M = (Mat_<float>(2, 3) << scale_ratio*cos(rot), -scale_ratio*sin(rot), this->landmark_input_size*0.5-center[0]*scale_ratio, scale_ratio*sin(rot), scale_ratio*cos(rot), this->landmark_input_size*0.5-center[1]*scale_ratio);
  136. Mat cropped;
  137. warpAffine(srcimg, cropped, M, cv::Size(this->landmark_input_size, this->landmark_input_size));
  138. face_align
  139. vector<cv::Mat> bgrChannels(3);
  140. split(cropped, bgrChannels);
  141. for (int c = 0; c < 3; c++)
  142. {
  143. bgrChannels[c].convertTo(bgrChannels[c], CV_32FC1);
  144. }
  145. const int image_area = this->landmark_input_size * this->landmark_input_size;
  146. this->aimg.resize(3 * image_area);
  147. size_t single_chn_size = image_area * sizeof(float);
  148. memcpy(this->aimg.data(), (float *)bgrChannels[0].data, single_chn_size);
  149. memcpy(this->aimg.data() + image_area, (float *)bgrChannels[1].data, single_chn_size);
  150. memcpy(this->aimg.data() + image_area * 2, (float *)bgrChannels[2].data, single_chn_size);
  151. Value input_tensor2 = Value::CreateTensor<float>(memory_info_handler, this->aimg.data(), this->aimg.size(), this->landmark_input_tensor_shape.data(), this->landmark_input_tensor_shape.size());
  152. vector<Value> landmark_ort_outputs = this->landmark_ort_session->Run(runOptions, this->landmark_input_names.data(), &input_tensor2, 1, this->landmark_output_names.data(), this->landmark_output_names.size());
  153. float *p_landmark = landmark_ort_outputs[0].GetTensorMutableData<float>();
  154. Mat IM;
  155. invertAffineTransform(M, IM);
  156. for(int k=0;k<106;k++)
  157. {
  158. float px = (p_landmark[k * 2] + 1) * this->landmark_input_size*0.5;
  159. float py = (p_landmark[k * 2 + 1] + 1) * this->landmark_input_size*0.5;
  160. boxes[i].landmark_2d_106[k * 2] = IM.at<float>(0, 0) * px + IM.at<float>(0, 1) * py + IM.at<float>(0, 2);
  161. boxes[i].landmark_2d_106[k * 2 + 1] = IM.at<float>(1, 0) * px + IM.at<float>(1, 1) * py + IM.at<float>(1, 2);
  162. }
  163. get_landmark
  164. }
  165. sort(boxes.begin(), boxes.end(), cmp);
  166. return boxes;
  167. }

天天代码码天天
微信公众号
.NET 人工智能实践
注:本文转载自blog.csdn.net的天天代码码天天的文章"https://lw112190.blog.csdn.net/article/details/141061879"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top