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. 转换算法
核心是 色度分量下采样。常用两种方法:
-
简单丢弃法(低复杂度)
丢弃偶数像素的 U、V,保留奇数像素的 UV 作为共用值:text
-
Pixel0 (Y0, U0, V0) → 输出 {Y0, U0} Pixel1 (Y1, U1, V1) → 输出 {Y1, V0} // 共享 Pixel0 的 V0 -
平均值法(质量更优)
计算两个像素 UV 的平均值:text
-
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}。 -
缓存
Y1和V_avg,下一周期输出。
-
-
周期3(状态0):
输出{Y1, V_avg},并准备缓存新像素。
注意:平均值法输出延迟较大(首像素需2周期),但色度信息保留更完整。
选择建议
-
简单丢弃法:适合对实时性要求高、资源受限的场景。
-
平均值法:适合对图像质量要求高的场景(如视频处理)。
可根据实际需求调整实现,例如支持其他YUV422子格式(如UYVY)。
3576

被折叠的 条评论
为什么被折叠?



