图像编辑器 Monica 之生成漫画风格的图像、以及使用 GPU 实现推理

一. 图像编辑器 Monica

Monica 是一款跨平台的桌面图像编辑软件(早期是为了验证一些算法而产生的)。

其技术栈如下:

  • Kotlin 编写 UI(Kotlin Compose Desktop 作为 UI 框架)
  • 基于 mvvm 模式,依赖注入使用 koin,编译使用 JDK 17
  • 部分算法使用 Kotlin 实现
  • 传统的 CV 算法使用 OpenCV C++ 来实现,Kotlin 通过 jni 来调用。
  • Monica 所使用的模型,主要使用 ONNXRuntime 来部署和加速模型,使用 C++ 实现。

Monica 目前还处于开发阶段,当前版本的可以参见 github 地址: github.com/fengzhizi71...

这个月我增加了生成多种漫画风格图像的功能,把使用 ONNXRuntime 部署的模型都支持使用 GPU 来加速推理。当然前提是需要有 N 卡。

二. 漫画风格

2.1 效果展示

Monica 将图片转换成动漫风格的模型使用 AnimeGANv3(github.com/TachibanaYo...)

下面展示该模块的入口

目前 Monica 集成了其5种动漫风格的模型。下面列举了几种风格的效果

除了人物之外,景色一样可以动漫化。

2.2 模型的加载、推理

下面展示 AnimeGANv3 相关模型的加载、推理方法,先定义一个 AnimeGAN 类

cpp 复制代码
#include <iostream>
#include <fstream>
#include <string>
#include <math.h>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
//#include <cuda_provider_factory.h>
#include <onnxruntime_cxx_api.h>
#include "../common/OnnxRuntimeBase.h"

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

class AnimeGAN: public OnnxRuntimeBase
{
public:
    AnimeGAN(std::string modelPath, const char* logId, const char* provider);

    void inferImage(Mat& src, Mat& dst);
private:
    const int inpWidth = 512;
    const int inpHeight = 512;
    const int outWidth = 512;
    const int outHeight = 512;
    vector<float> input_image_;
};

然后实现该类

cpp 复制代码
#include "../../include/cartoon/AnimeGAN.h"

AnimeGAN::AnimeGAN(string modelPath, const char* logId, const char* provider): OnnxRuntimeBase(modelPath, logId, provider)
{
}

// 工具函数:将 OpenCV 的 Mat 转为 float tensor(NCHW)
std::vector<float> prepare_input_nhwc(const cv::Mat& img) {
    std::vector<float> input_tensor_values;
    for (int y = 0; y < img.rows; ++y) {
        for (int x = 0; x < img.cols; ++x) {
            for (int c = 0; c < 3; ++c) {
                input_tensor_values.push_back(img.at<cv::Vec3f>(y, x)[c]);
            }
        }
    }
    return input_tensor_values;
}


// 工具函数:将输出 tensor 转为 Mat
cv::Mat tensor_to_mat_nhwc(const float* data, int h, int w) {
    cv::Mat output(h, w, CV_32FC3);
    int idx = 0;
    for (int y = 0; y < h; ++y) {
        for (int x = 0; x < w; ++x) {
            for (int c = 0; c < 3; ++c) {
                output.at<cv::Vec3f>(y, x)[c] = data[idx++];
            }
        }
    }
    return output;
}

void AnimeGAN::inferImage(Mat& src, Mat& dst)
{
    int w = src.cols;
    int h = src.rows;

    Mat temp;
    resize(src, temp, Size(this->inpWidth, this->inpHeight));
    temp.convertTo(temp, CV_32F, 1.0 / 255.0); // 归一化 [0,1]

    // 创建输入 tensor 数据
    std::vector<float> input_tensor_values = prepare_input_nhwc(temp);
    std::array<int64_t, 4> input_shape = {1, temp.rows, temp.cols, 3};

    Ort::MemoryInfo allocator_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
    Ort::Value input_tensor_ = Ort::Value::CreateTensor<float>(allocator_info, input_tensor_values.data(), input_tensor_values.size(), input_shape.data(), input_shape.size());

    vector<Value> ort_outputs = this -> forward(input_tensor_);

    // 取出输出数据
    float* output_data = ort_outputs.front().GetTensorMutableData<float>();
    dst = tensor_to_mat_nhwc(output_data, outHeight, outWidth);

    // 后处理输出图像
    dst = cv::min(cv::max(dst, 0.0f), 1.0f); // clamp 到 [0,1]
    dst.convertTo(dst, CV_8UC3, 255.0);      // 转回 [0,255]

    cv::resize(dst, dst, cv::Size(w, h));
}

通过 AnimeGAN 类就可以使用相关模型来推理,将图像转换成漫画的风格。

三. 使用 GPU 推理

在使用 GPU 做推理时,需要有个前提就是确保安装了 CUDA、cuDNN 以及 CUDA 对应的 ONNXRuntime 版本。

使用nvidia-smi命令获取 GPU 的相关信息。

然后查看 CUDA 版本

sql 复制代码
nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2021 NVIDIA Corporation
Built on Wed_Jun__2_19:15:15_PDT_2021
Cuda compilation tools, release 11.4, V11.4.48
Build cuda_11.4.r11.4/compiler.30033411_0

查看 cuDNN 版本

arduino 复制代码
cat /usr/local/cuda/include/cudnn_version.h | grep CUDNN_MAJOR -A 2
#define CUDNN_MAJOR 8
#define CUDNN_MINOR 2
#define CUDNN_PATCHLEVEL 4

确保上述版本都兼容之后(版本不兼容会有各种问题),在 CMake 中添加判断当前系统是否支持 CUDA

scss 复制代码
# 定义一个开关变量用于控制是否启用 CUDA
set(ENABLE_CUDA OFF)
# 针对不同平台进行判断
if(APPLE)
    message(STATUS "当前平台:macOS(不支持 CUDA,使用 CPU 版本)")
    set(ENABLE_CUDA OFF)
elseif(WIN32 OR UNIX)
    # 在 Windows/Linux 上查找 CUDA 工具包(推荐使用 CUDAToolkit 模块)
    find_package(CUDAToolkit QUIET)
    if(CUDAToolkit_FOUND)
        message(STATUS "CUDA 工具包已找到,使用 GPU 版本")
        set(ENABLE_CUDA ON)
    else()
        message(STATUS "未找到 CUDA 工具包,使用 CPU 版本")
    endif()
else()
    message(STATUS "未知平台,默认使用 CPU 版本")
    set(ENABLE_CUDA OFF)
endif()

针对不同的环境,配置不同的 ONNXRuntime 版本

scss 复制代码
    # 指定ONNX Runtime的路径
    if(ENABLE_CUDA)
        set(ONNXRUNTIME_ROOT "/home/xxx/onnxruntime/onnxruntime-linux-x64-gpu-1.10.0")
    else()
        set(ONNXRUNTIME_ROOT "/home/xxx/onnxruntime/onnxruntime-linux-x64-1.10.0")
    endif()

然后再设置统一的编译选项或宏定义,用于在源代码中区分不同分支

scss 复制代码
    if(ENABLE_CUDA)
        target_compile_definitions(${LINUX_PROJECT_NAME} PRIVATE USE_GPU)
    endif()

最后,在源代码中加载模型的时候区分一下是否支持 GPU

cpp 复制代码
#ifdef USE_GPU
    const string& onnx_provider = OnnxProviders::CUDA;
#else
    const string& onnx_provider = OnnxProviders::CPU;
#endif

详细的代码可以在这里找到: github.com/fengzhizi71...

四. 总结

Monica 后续的重点是重构形状绘制模块,增加人脸美化的功能,引入一些有趣的模型,以及优化软件的各种使用体验。

当然,还有尽快解决 Mac 打包的问题,给出各个平台的安装包。

Monica github 地址:github.com/fengzhizi71...

相关推荐
BFT白芙堂3 分钟前
Franka Research 3 进阶应用:基于神经网络的 ORACLE 交互控制策略深度解析
人工智能·深度学习·神经网络·oracle·机器人·人机交互·vr
智算菩萨4 分钟前
自然语言处理常用Python库:spaCy使用全解
人工智能·python·自然语言处理
Katecat996637 分钟前
【工业视觉检测】基于YOLOv8的皮带输送机关键部件检测与识别系统完整实现
人工智能·yolo·视觉检测
2401_841495648 分钟前
【自然语言处理】自然语言处理(NLP)的全景应用:从生活便利到产业革新的全维度渗透
人工智能·自然语言处理·大语言模型·多模态融合·统计学习·规则驱动·通用语言智能
deephub9 分钟前
ONNX Runtime Python 推理性能优化:8 个低延迟工程实践
开发语言·人工智能·python·神经网络·性能优化·onnx
AdMergeX10 分钟前
AdMergeX旗下 Funlink SDK通过中国信通院双端安全专项检验
大数据·人工智能·安全·saas·广告saas·流量变现
大模型实验室Lab4AI10 分钟前
Qwen-Video-8B与LLaMA-Factory联动实现垂类视频理解
人工智能·音视频·llama
AI营销资讯站11 分钟前
原圈科技引领AI营销内容生产平台革新,技术与行业高度适配
人工智能
艾莉丝努力练剑12 分钟前
【Linux进程(四)】深入理解 Linux O(1) 调度器:双队列轮转与进程优先级机制——如何避免进程饥饿,实现公平且高效的进程调度
java·大数据·linux·运维·服务器·人工智能·安全
智驱力人工智能13 分钟前
守护生命的水上之眼 无人机人员落水检测系统的技术攻坚与应用实践 无人机溺水识别 山区水库无人机落水检测系统 水域安全无人机部署指南
大数据·人工智能·算法·安全·无人机·边缘计算