YUV444转YUV422算法实现

YUV444 转 YUV422 的算法原理与 Verilog 实现

1. 格式差异
  • YUV444:每个像素独立存储 Y、U、V 分量(24bpp,顺序通常为 Y[23:16], U[15:8], V[7:0])。

  • YUV422:水平相邻的两个像素共享 U、V 分量(16bpp,以 YUYV 格式为例,数据排列为 Y0, U0, Y1, V0)。

2. 转换算法

核心是 色度分量下采样。常用两种方法:

  1. 简单丢弃法(低复杂度)
    丢弃偶数像素的 U、V,保留奇数像素的 UV 作为共用值:

    text

  • Pixel0 (Y0, U0, V0) → 输出 {Y0, U0}  
    Pixel1 (Y1, U1, V1) → 输出 {Y1, V0}  // 共享 Pixel0 的 V0
  • 平均值法(质量更优)
    计算两个像素 UV 的平均值:

    text

  1. U_avg = (U0 + U1) >> 1
    V_avg = (V0 + V1) >> 1
    输出序列:{Y0, U_avg}, {Y1, V_avg}

Verilog 实现(简单丢弃法)

设计要点
  • 输入:每周期 24-bit YUV444 数据(data_in)。

  • 输出:每周期 16-bit YUV422 数据(data_out)。

  • 时序:用 flip 标志区分奇数/偶数像素,寄存奇数像素的 V 分量。

verilog

module yuv444_to_yuv422 (
    input  wire        clk,       // 时钟
    input  wire        reset,     // 复位
    input  wire [23:0] data_in,   // 输入数据 (Y[23:16], U[15:8], V[7:0])
    input  wire        valid_in,  // 输入有效标志
    output reg  [15:0] data_out,  // 输出数据 (YUV422, 16-bit)
    output reg         valid_out  // 输出有效标志
);

reg        flip;      // 像素位置标志 (0: 奇数像素, 1: 偶数像素)
reg [7:0]  reg_V;     // 寄存奇数像素的 V 分量

always @(posedge clk) begin
    if (reset) begin
        flip       <= 0;
        reg_V      <= 0;
        data_out   <= 0;
        valid_out  <= 0;
    end else begin
        valid_out <= valid_in;  // 输出有效与输入同步
        if (valid_in) begin
            if (flip == 0) begin
                // 奇数像素: 输出 {Y, U}, 寄存 V
                data_out <= {data_in[23:16], data_in[15:8]};  // {Y0, U0}
                reg_V    <= data_in[7:0];                     // 保存 V0
                flip     <= 1;  // 下一周期为偶数像素
            end else begin
                // 偶数像素: 输出 {Y, 寄存的 V} (共享前一个像素的 V)
                data_out <= {data_in[23:16], reg_V};  // {Y1, V0}
                flip     <= 0;  // 下一周期为奇数像素
            end
        end
    end
end

endmodule
时序说明
  • 周期1(奇数像素)
    输入 {Y0, U0, V0} → 输出 {Y0, U0},寄存 V0

  • 周期2(偶数像素)
    输入 {Y1, U1, V1} → 输出 {Y1, V0}(丢弃 U1/V1)。

  • 输出流格式{Y0, U0}, {Y1, V0}, {Y2, U2}, {Y3, V2}, ...


Verilog 实现(平均值法)

设计要点
  • 需缓存第一个像素的 YUV。

  • 在第二个像素到来时计算 UV 平均值。

verilog

module yuv444_to_yuv422_avg (
    input  wire        clk,
    input  wire        reset,
    input  wire [23:0] data_in,
    input  wire        valid_in,
    output reg  [15:0] data_out,
    output reg         valid_out
);

reg         state;           // 状态 (0: 等待第一个像素, 1: 等待第二个像素)
reg [23:0]  reg_pixel0;      // 缓存第一个像素 (Y0, U0, V0)

always @(posedge clk) begin
    if (reset) begin
        state      <= 0;
        reg_pixel0 <= 0;
        data_out   <= 0;
        valid_out  <= 0;
    end else begin
        valid_out <= 0;  // 默认输出无效
        if (valid_in) begin
            if (state == 0) begin
                // 状态0: 缓存第一个像素,不输出
                reg_pixel0 <= data_in;
                state      <= 1;
            end else begin
                // 状态1: 计算平均值并输出两个16-bit数据
                reg [7:0] U_avg = (reg_pixel0[15:8] + data_in[15:8]) >> 1;
                reg [7:0] V_avg = (reg_pixel0[7:0]  + data_in[7:0])  >> 1;
                
                // 输出第一个16-bit: {Y0, U_avg}
                data_out   <= {reg_pixel0[23:16], U_avg};
                valid_out  <= 1;  // 标记有效
                
                // 下一周期输出第二个16-bit: {Y1, V_avg}
                reg_pixel0 <= {data_in[23:16], 8'd0, V_avg}; // 暂存 Y1 和 V_avg
                state      <= 0;  // 下一周期返回状态0
            end
        end
    end
end

endmodule
时序说明
  • 周期1(状态0)
    缓存 Pixel0 {Y0, U0, V0},无输出。

  • 周期2(状态1)
    输入 Pixel1 {Y1, U1, V1}

    • 计算 U_avg = (U0 + U1)/2, V_avg = (V0 + V1)/2

    • 输出 {Y0, U_avg}

    • 缓存 Y1V_avg,下一周期输出。

  • 周期3(状态0)
    输出 {Y1, V_avg},并准备缓存新像素。

注意:平均值法输出延迟较大(首像素需2周期),但色度信息保留更完整。


选择建议

  • 简单丢弃法:适合对实时性要求高、资源受限的场景。

  • 平均值法:适合对图像质量要求高的场景(如视频处理)。
    可根据实际需求调整实现,例如支持其他YUV422子格式(如UYVY)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值