#图像转换 #颜色转换 #格式转换 #RGB #YUV #视频 #转换器

dcv-color-primitives

用于执行图像颜色模型转换的库

28 个版本

0.6.1 2023 年 11 月 3 日
0.5.4 2023 年 6 月 6 日
0.5.3 2023 年 3 月 7 日
0.5.1 2022 年 6 月 28 日
0.1.0 2019 年 12 月 23 日

图像 中排名第 22

Download history 1218/week @ 2024-04-23 1404/week @ 2024-04-30 1963/week @ 2024-05-07 1448/week @ 2024-05-14 2116/week @ 2024-05-21 1590/week @ 2024-05-28 1504/week @ 2024-06-04 1937/week @ 2024-06-11 1561/week @ 2024-06-18 1684/week @ 2024-06-25 864/week @ 2024-07-02 1419/week @ 2024-07-09 1536/week @ 2024-07-16 1514/week @ 2024-07-23 2129/week @ 2024-07-30 1607/week @ 2024-08-06

每月下载量 6,933
7 个 crate 中使用(直接使用 2 个)

MIT-0 许可证

375KB
7.5K SLoC

Rust 6K SLoC // 0.1% comments C 1.5K SLoC // 0.1% comments Python 300 SLoC // 0.1% comments PowerShell 43 SLoC // 0.3% comments Shell 15 SLoC // 0.5% comments

DCV Color Primitives - dcp

Build Status MIT licensed crates.io documentation Coverage Status

DCV Color Primitives 是一个执行图像颜色模型转换的库。

设计指南

  • 了解底层硬件和补充 CPU 扩展集(最高 avx2)
  • 支持来自单个缓冲区或多个图像平面的数据
  • 支持非紧密打包数据
  • 支持大于 4GB 的图像(64 位)
  • 支持 ARM(aarch64)[*]
  • 支持 WebAssembly[*]

[*]: 补充 CPU 扩展集尚未支持。

图像格式转换

该库目前能够转换以下像素格式

源像素格式 目标像素格式
ARGB I420, I444, NV12
BGR I420, I444, NV12, RGB
BGRA I420, I444, NV12, RGB
I420 BGRA, RGBA
I444 BGRA, RGBA
NV12 BGRA, RGB, RGBA
RGB BGRA

颜色模型

支持的颜色模型包括

  • YCbCr,ITU-R 建议BT.601(标准视频系统)
  • YCbCr,ITU-R 建议BT.709(CSC 系统)

支持标准范围(0-235)和全范围(0-255)。

要求

  • Rust 1.70 及更高版本

Windows

Linux

可能需要管理员权限。

构建

在库根目录内打开终端。

为调试体验构建

cargo build

构建优化库

cargo build --release

运行单元测试

cargo test

运行基准测试

cargo bench

高级基准模式。有两个基准脚本

  • run-bench.ps1 用于 Windows
  • run-bench.sh 用于 Linux 和 MacOS

它们通过减少由于以下因素引起的方差,可以获得比cargo bench更稳定的结果:

  • CPU迁移
  • 文件系统缓存
  • 进程优先级

此外,Linux脚本支持硬件性能计数器,例如,可以输出消耗的CPU周期而不是经过的时间。

Linux示例

./run-bench -c 1 # runs cargo bench and outputs CPU cycles
./run.bench -c 1 -p "/i420" # runs cargo bench, output CPU cycles, filtering tests that contains '/i420'

WebAssembly

安装所需的依赖项

rustup target add wasm32-unknown-unknown

为调试体验构建

cargo build --target wasm32-unknown-unknown

要测试,请确保您已安装wasm-pack。然后

wasm-pack test --node

用法

图像转换

将图像从bgra转换为包含bt601 yuv的单平面nv12格式

use dcv_color_primitives as dcp;
use dcp::{convert_image, ColorSpace, ImageFormat, PixelFormat};

fn main() {
    const WIDTH: u32 = 640;
    const HEIGHT: u32 = 480;

    let src_data = Box::new([0u8; 4 * (WIDTH as usize) * (HEIGHT as usize)]);
    let mut dst_data = Box::new([0u8; 3 * (WIDTH as usize) * (HEIGHT as usize) / 2]);

    let src_format = ImageFormat {
        pixel_format: PixelFormat::Bgra,
        color_space: ColorSpace::Rgb,
        num_planes: 1,
    };

    let dst_format = ImageFormat {
        pixel_format: PixelFormat::Nv12,
        color_space: ColorSpace::Bt601,
        num_planes: 1,
    };

    convert_image(
        WIDTH,
        HEIGHT,
        &src_format,
        None,
        &[&*src_data],
        &dst_format,
        None,
        &mut [&mut *dst_data],
    );
}

错误处理

库函数返回一个描述操作结果的Result

结果 描述
Ok(()) 操作成功
Err(ErrorKind::InvalidValue) 一个或多个参数对调用函数无效
Err(ErrorKind::InvalidOperation) 调用函数不支持参数组合
Err(ErrorKind::NotEnoughData) 一个或多个缓冲区大小不正确

在以下示例中,result将匹配Err(ErrorKind::InvalidValue),因为ColorSpace::Bt709颜色空间与PixelFormat::Bgra不兼容

use dcv_color_primitives as dcp;
use dcp::{convert_image, ColorSpace, ErrorKind, ImageFormat, PixelFormat};

fn main() {
    const WIDTH: u32 = 640;
    const HEIGHT: u32 = 480;

    let src_data = Box::new([0u8; 4 * (WIDTH as usize) * (HEIGHT as usize)]);
    let mut dst_data = Box::new([0u8; 3 * (WIDTH as usize) * (HEIGHT as usize) / 2]);

    let src_format = ImageFormat {
        pixel_format: PixelFormat::Bgra,
        color_space: ColorSpace::Bt709,
        num_planes: 1,
    };

    let dst_format = ImageFormat {
        pixel_format: PixelFormat::Nv12,
        color_space: ColorSpace::Bt601,
        num_planes: 1,
    };

    let status = convert_image(
        WIDTH,
        HEIGHT,
        &src_format,
        None,
        &[&*src_data],
        &dst_format,
        None,
        &mut [&mut *dst_data],
    );

    match status {
        Err(ErrorKind::InvalidValue) => (),
        _ => panic!("Expected ErrorKind::InvalidValue"),
    }
}

更好的是,您可能希望将错误传播到调用函数或与其他错误类型混合

use dcv_color_primitives as dcp;
use dcp::{convert_image, ColorSpace, ImageFormat, PixelFormat};
use std::error;

fn main() -> Result<(), Box<dyn error::Error>> {
    const WIDTH: u32 = 640;
    const HEIGHT: u32 = 480;

    let src_data = Box::new([0u8; 4 * (WIDTH as usize) * (HEIGHT as usize)]);
    let mut dst_data = Box::new([0u8; 3 * (WIDTH as usize) * (HEIGHT as usize) / 2]);

    let src_format = ImageFormat {
        pixel_format: PixelFormat::Bgra,
        color_space: ColorSpace::Bt709,
        num_planes: 1,
    };

    let dst_format = ImageFormat {
        pixel_format: PixelFormat::Nv12,
        color_space: ColorSpace::Bt601,
        num_planes: 1,
    };

    convert_image(
        WIDTH,
        HEIGHT,
        &src_format,
        None,
        &[&*src_data],
        &dst_format,
        None,
        &mut [&mut *dst_data],
    )?;

    Ok(())
}

缓冲区大小计算

到目前为止,缓冲区的大小是根据图像像素格式和尺寸来确定的;然而,您可以使用一个函数来计算存储给定格式和尺寸的图像所需的字节数

use dcv_color_primitives as dcp;
use dcp::{get_buffers_size, ColorSpace, ImageFormat, PixelFormat};
use std::error;

fn main() -> Result<(), Box<dyn error::Error>> {
    const WIDTH: u32 = 640;
    const HEIGHT: u32 = 480;
    const NUM_PLANES: u32 = 1;

    let format = ImageFormat {
        pixel_format: PixelFormat::Bgra,
        color_space: ColorSpace::Rgb,
        num_planes: NUM_PLANES,
    };

    let sizes: &mut [usize] = &mut [0usize; NUM_PLANES as usize];
    get_buffers_size(WIDTH, HEIGHT, &format, None, sizes)?;

    let buffer: Vec<_> = vec![0u8; sizes[0]];

    // Do something with buffer
    // --snip--

    Ok(())
}

图像平面

如果您的数据分散在多个缓冲区中,这些缓冲区不一定连续,您可以提供图像平面

use dcv_color_primitives as dcp;
use dcp::{convert_image, get_buffers_size, ColorSpace, ImageFormat, PixelFormat};
use std::error;

fn main() -> Result<(), Box<dyn error::Error>> {
    const WIDTH: u32 = 640;
    const HEIGHT: u32 = 480;
    const NUM_SRC_PLANES: u32 = 2;
    const NUM_DST_PLANES: u32 = 1;

    let src_format = ImageFormat {
        pixel_format: PixelFormat::Nv12,
        color_space: ColorSpace::Bt709,
        num_planes: NUM_SRC_PLANES,
    };

    let src_sizes: &mut [usize] = &mut [0usize; NUM_SRC_PLANES as usize];
    get_buffers_size(WIDTH, HEIGHT, &src_format, None, src_sizes)?;

    let src_y: Vec<_> = vec![0u8; src_sizes[0]];
    let src_uv: Vec<_> = vec![0u8; src_sizes[1]];

    let dst_format = ImageFormat {
        pixel_format: PixelFormat::Bgra,
        color_space: ColorSpace::Rgb,
        num_planes: NUM_DST_PLANES,
    };

    let dst_sizes: &mut [usize] = &mut [0usize; NUM_DST_PLANES as usize];
    get_buffers_size(WIDTH, HEIGHT, &dst_format, None, dst_sizes)?;

    let mut dst_rgba: Vec<_> = vec![0u8; dst_sizes[0]];

    convert_image(
        WIDTH,
        HEIGHT,
        &src_format,
        None,
        &[&src_y[..], &src_uv[..]],
        &dst_format,
        None,
        &mut [&mut dst_rgba[..]],
    )?;

    Ok(())
}

Stride支持

为了考虑非紧密打包的数据,您可以提供图像Stride

use dcv_color_primitives as dcp;
use dcp::{convert_image, get_buffers_size, ColorSpace, ImageFormat, PixelFormat};
use std::error;

fn main() -> Result<(), Box<dyn error::Error>> {
    const WIDTH: u32 = 640;
    const HEIGHT: u32 = 480;
    const NUM_SRC_PLANES: u32 = 1;
    const NUM_DST_PLANES: u32 = 2;
    const RGB_STRIDE: usize = 4 * (((3 * (WIDTH as usize)) + 3) / 4);

    let src_format = ImageFormat {
        pixel_format: PixelFormat::Bgr,
        color_space: ColorSpace::Rgb,
        num_planes: NUM_SRC_PLANES,
    };

    let src_strides: &[usize] = &[RGB_STRIDE];

    let src_sizes: &mut [usize] = &mut [0usize; NUM_SRC_PLANES as usize];
    get_buffers_size(WIDTH, HEIGHT, &src_format, Some(src_strides), src_sizes)?;

    let src_rgba: Vec<_> = vec![0u8; src_sizes[0]];

    let dst_format = ImageFormat {
        pixel_format: PixelFormat::Nv12,
        color_space: ColorSpace::Bt709,
        num_planes: NUM_DST_PLANES,
    };

    let dst_sizes: &mut [usize] = &mut [0usize; NUM_DST_PLANES as usize];
    get_buffers_size(WIDTH, HEIGHT, &dst_format, None, dst_sizes)?;

    let mut dst_y: Vec<_> = vec![0u8; dst_sizes[0]];
    let mut dst_uv: Vec<_> = vec![0u8; dst_sizes[1]];

    convert_image(
        WIDTH,
        HEIGHT,
        &src_format,
        Some(src_strides),
        &[&src_rgba[..]],
        &dst_format,
        None,
        &mut [&mut dst_y[..], &mut dst_uv[..]],
    )?;

    Ok(())
}

有关更多信息,请参阅文档。

C绑定

DCV颜色原语提供C绑定。默认构建将自动生成静态库。

为了在您的应用程序库中包含DCV颜色原语,您需要

  • 静态链接到dcv_color_primitives
  • 对于Windows,链接到ws2_32.lib、userenv.lib、bcrypt.lib和ntdll.lib
  • 对于Linux,链接到libdl和libm

API与Rust略有不同。请检查dcv_color_primitives.h以获取示例和更多信息。

提供了一个meson构建系统,用于构建静态库并将其与包含文件和pkgconfig文件一起安装。还有一些用C编写的单元测试,以添加一些绑定覆盖率。以下提供了最小指令,有关更多信息,请参阅meson的帮助文档

  • Windows 需要Visual Studio。至少需要以下包:

    • MSBuild
    • MSVC - C++构建工具
    • Windows 10 SDK

    安装meson,您可以选择以下方法之一

    1. 使用meson msi安装程序
    1. 通过pip安装meson

    注意:最低要求的meson版本是1.0.0。

    所有构建命令都必须在VS(x86或x64取决于您要构建的平台)的本地工具命令提示符中发出

  • Linux 以下示例针对Ubuntu

    #install python3
    apt install python3
    
    #install meson. See https://mesonbuild.com/Getting-meson.html for details or if you want to install through pip.
    apt install meson
    
    #install ninja
    apt install ninja-build
    

    可能需要管理员权限。

  • 构建 将目录移动到库根目录

    cd `dcv_color_primitives_root_dir`
    

    然后

    meson setup --buildtype release builddir
    ninja -C builddir
    
  • 运行测试

    cd builddir
    meson test -t 10
    

    需要10倍的超时时间因子,因为一些测试的完成时间超过了默认的30秒。

  • 安装

    ninja -C builddir install
    

许可证

此库受MIT-0许可证的许可。请参阅LICENSE文件。

依赖项

~220KB