stb_image jpg解码 RVV优化和在 milkv-duo 上的测试

来源:转载自https://forum.sophgo.com/t/stb-image-jpg-rvv-milkv-duo/240,原作者nihui

stb_image jpg解码 RVV优化和在 milkv-duo 上的测试

TL;DR

GitHub

你可以:

  • 拿出 opencv-mobile 项目里的 RVV 优化版 stb_image.h 配合 #define STBI_RVV + stbi_load

或者你也可以:

  • 直接使用编译好的 opencv-mobile-4.8.0-milkv-duo.zip,他的 cv::imread 已经包含jpg解码RVV优化

stb_image

GitHub

小而美的图像库 stb_image,没有任何依赖,include 一个 .h 文件就能实现 JPG PNG 等常用格式解码

相比于 libjpeg libpng,stb_image 移植极度方便,接口十分简单即 stbi_load

opencv-mobile 项目中的 highgui 模块利用 stb_image 实现图片读写功能

stb_image.h 中有 x86 sse2 和 arm neon 的加速代码,没有 risc-v vector 优化

相当多的 risc-v 芯片带有 npu,但图像解码依旧要靠 cpu,因此十分有必要优化一下下

stb_image RVV 优化过程中的一点点吐嘈

具体实现细节就不bb了,想了解的人直接看源码

github.com/nihui/opencv-mobile

  • idct 中间有个 16bit transpose 8x8,sse2/neon 指令集都有多寄存器之间的 shuffle/zip 指令,实现多个寄存器的 transpose,但是 RVV 只有单寄存器内 shuffle 的 vgather,这就很难搞了啊。RVV 你也不学着点,看看人家 arm SVE 同样变长宽度simd就有zip,你就只能 stride save + load 从内存倒腾一遍,真是败笔。

(什么?你说你 RVV 可以 compress + merge 或者 left shift + widen add 来搞 shuffle?你也不嫌丑?)

  • 128bit 宽度的时候,8个uchar 应该是 vuint8mf2_t 表示,但是 RVV-0.7.1 的工具链遇到 mf2 的东西就罢工,于是只能用 vuint8m1_t 浪费高半部分的计算

stbimage jpg加载测试

简单写个计时函数,循环调用 stbi_load 加载 1280x720 分辨率的 jpg 图片,输出接口耗时(ms)

在 include 前定义 STBI_RVV 开启优化!

#include  //gettimeofday()
#include    // sleep()

#define STB_IMAGE_IMPLEMENTATION
#define STBI_RVV
#include "stb_image.h"

double get_current_time()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);

    return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
}

int main()
{
    for (int i = 0; i < 10; i++)
    {
        double t0 = get_current_time();

        int desired_channels = 3;
        int w;
        int h;
        int c;
        unsigned char* pixeldata = stbi_load("in.jpg", &w, &h, &c, desired_channels);

        double t1 = get_current_time();

        stbi_image_free(pixeldata);

        fprintf(stderr, "%.3f\n", t1-t0);
    }

    return 0;
}

在 milkv-duo 实测下开不开 STBI_RVV 区别

[root@milkv]~# ./stbimage-test
214.697
219.526
214.598
214.787
216.354
214.875
217.516
214.868
217.323
214.912

[root@milkv]~# ./stbimage-test-rvv
149.423
152.059
149.017
148.450
150.817
148.090
148.167
150.507
147.775
147.381

opencv-mobile jpg加载测试和结果验证

优化后的 stb_image 更新到 opencv-mobile 里头,为 cv::imread / cv::imdecode 带来提速,同时保存解码后的图片,验证结果是否一致

#include  //gettimeofday()
#include    // sleep()

#include 
#include 
#include 

double get_current_time()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);

    return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
}

int main()
{
    for (int i = 0; i < 10; i++)
    {
        double t0 = get_current_time();

        cv::Mat bgr = cv::imread("in.jpg", 1);

        double t1 = get_current_time();

        fprintf(stderr, "%.3f\n", t1-t0);

        if (i == 9)
        {
            cv::resize(bgr, bgr, cv::Size(200, 200));
            cv::imwrite("out-rvv.jpg", bgr);
        }
    }

    return 0;
}

在 milkv-duo 实测下开不开 STBI_RVV 区别

[root@milkv]~# LD_LIBRARY_PATH=. ./opencv-mobile-test
279.231
275.922
278.366
275.949
278.956
278.733
275.571
278.167
275.566
279.943

[root@milkv]~# LD_LIBRARY_PATH=. ./opencv-mobile-test-rvv
226.102
221.550
224.004
220.458
223.346
220.088
219.719
221.991
218.758
222.004

stb_image jpg解码 RVV优化和在 milkv-duo 上的测试_第1张图片

opencv-mobile cv::imread 相对于 stb_image stbi_load 多了 memcpy 和 RGB2BGR 转换的代价

RVV优化后的保存图片,md5sum完全一致!

[nihui@nihui-pc build]$ md5sum out*
a70cc79b13daeddd8b20e31a2fd5f0c6  out.jpg
a70cc79b13daeddd8b20e31a2fd5f0c6  out-rvv.jpg

图片内容也是正常的

stb_image jpg解码 RVV优化和在 milkv-duo 上的测试_第2张图片
最后,如果觉得有用请star和转发

你可能感兴趣的:(SOPHGO设备硬件,技术内容活动,硬件工程)