添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

小而美的图像库 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 <sys/time.h> //gettimeofday()
    #include <unistd.h>   // 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 <sys/time.h> //gettimeofday()
    #include <unistd.h>   // sleep()
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    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
    

    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
    

    图片内容也是正常的

    最后,如果觉得有用请star和转发