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

一. 图像编辑器 Monica

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

其技术栈如下:

  • Kotlin 编写 UI(Kotlin Compose Desktop 作为 UI 框架)

  • 基于 mvvm 模式,依赖注入使用 koin,编译使用 JDK 17

  • 部分算法使用 Kotlin 实现

  • 传统的 CV 算法使用 OpenCV C++ 来实现,Kotlin 通过 jni 来调用。

  • Monica 所使用的模型,主要使用 ONNXRuntime 来部署和加速模型,使用 C++ 实现。

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

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

二. 漫画风格

2.1 效果展示

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

下面展示该模块的入口

目前 Monica 集成了其5种动漫风格的模型。下面列举了几种风格的效果
黑白线稿.png 可爱风格.png

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

2.2 模型的加载、推理

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

go 复制代码
#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"

usingnamespace cv;
usingnamespacestd;
usingnamespace Ort;

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

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

然后实现该类

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

AnimeGAN::AnimeGAN(string modelPath, constchar* logId, constchar* 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 版本

go 复制代码
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 版本

go 复制代码
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

go 复制代码
# 定义一个开关变量用于控制是否启用 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 版本

go 复制代码
# 指定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()

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

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

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

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

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

四. 总结

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

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

Monica github 地址:https://github.com/fengzhizi715/Monica

相关推荐
吞掉星星的鲸鱼5 小时前
VScode安装codex
ide·vscode·编辑器
claider5 小时前
Vim User Manual 阅读笔记 User_03.txt move around
笔记·编辑器·vim
啊湘6 小时前
VSCODE英文界面切换为中文(适用CURSOR等使用)
ide·vscode·编辑器·bug·cursor
wincheshe10 小时前
React Native inspector 点击组件跳转编辑器技术详解
react native·react.js·编辑器
微醺的老虎1 天前
【工具】vscode格式化json文件
ide·vscode·编辑器
乔宕一1 天前
vscode 设置每次调试 powershell 脚本都使用临时的 powershell 终端
ide·vscode·编辑器
山峰哥1 天前
数据库工程与SQL调优实战:从原理到案例的深度解析
java·数据库·sql·oracle·性能优化·编辑器
m0_466607701 天前
IAR Embedded Workbench (EWARM) 项目中的关键文件
编辑器
阴暗扭曲实习生1 天前
135编辑器字符效果:上标数字与特殊字体实现步骤
编辑器
猫头虎2 天前
Claude Code 永动机:ralph-loop 无限循环迭代插件详解(安装 / 原理 / 最佳实践 / 避坑)
ide·人工智能·langchain·开源·编辑器·aigc·编程技术