基于FPGA的系统通过合成两条视频流来提供3D视频
齐误差
为了简化系统并减少合并两幅图像所需存储器,到达FPGA的数据应进行同步,以使来自第一台摄像机的第M 行第N个 像素与来自第二台摄像机的第M 行第N个 像素同时收到。
在FPGA输入端,这可能很难实现,因为两条视频路径可能具有不同的延迟:行锁定摄像机可能输出存在对齐误差的行,不同的连接长度可能加大对齐误差,而视频解码器则可能带来可变启动延迟。受这些延迟影响,采用行锁定摄像机的系统会有一些存在对齐误差的像素。
行锁定摄像机对齐误差
即使是行锁定摄像机也可能输出存在对齐误差的视频行。图8显示来自两台摄像机的CVBS输出端的垂直同步信号。一台摄像机(同步主 机)为第二台摄像机(同步从机)提供行锁定信号。380 ns的对齐误差是清楚可见的。图9展示的是这些摄像机输出端的视频解码器传输的数据。可以看到11个像素的位移。
图8 行锁定视频摄像机之间的380 ns视频对齐误差
图9 数字域中未补偿的11个像素的视频对齐误差
不同的连接长度
所有电气连接都会带来传播延迟,因此,要确保两条视频路径具有相同的轨道和电缆长度。
视频解码器/HDMI接收器延迟
所有视频解码器都会带来可能因启用的功能而异的延迟。另外,有些视频器件含有可能增加随机启动延迟的因素——如深色FIFO。采用视频 解码器的典型立体系统的随机启动延迟大约为5个像素时钟。含有HDMI发射器和接收器的系统(如图10所示)的随机启动延迟可能为40个像素时钟左右。
图10 流水线延迟测量设置
对齐误差补偿
图11所示系统中,一个视频解码器对来自各摄像机的模拟信号进行数字化处理。各视频路径的数据和时钟是独立的。两条视频路径都连接至 FIFO,后者对输入数据进行缓冲,以补偿数据对齐误差。在输出数据时,FIFO使用来自其中一个解码器的共用时钟。在锁定系统中,两条数据路径应具有完 全相同的时钟频率,以确保在摄像机行锁定且视频解码器锁定的情况下,不会出现FIFO溢出或下溢现象。
通过启用或禁用FIFO输出,控制模块可以维持FIFO电平以尽量减少像素对齐误差。如果采取了正确的补偿措施,则FPGA模块的输出应为与第一个像素对齐的两条数据路径。然后该数据提供给FPGA后端,以生成3D格式。
图11 使用数字FIFO来重新对齐视频图像
对齐误差测量
两个数字化数据流之间的对齐误差可以在视频FIFO输出端进行测量,其方法是使用一个单一时钟计数器,该计数器在输入信号之一的垂直同 步(VS)脉冲上复位。图12所示两个视频流(vs_a_in和vs_b_in)的对齐误差为4个像素。计数器使用列表1中所示方法测量对齐误差。计数从 VS1的上升沿开始,并在VS2的上升沿终止。
如果一个帧的总像素长度是已知的,则可以通过从帧长中减去计数值,从而算出负偏斜(VS2位于VS1之前)。该负值应在偏斜超过像素帧长的一半时计算。结果应用来重新对齐FIFO中存储的数据。
图12 对齐误差测量
列表1 简单对齐误差测量(Verilog®)。
module misalign_measurement(
input wire reset,
input wire clk_in,
input wire vs_a_in,
input wire vs_b_in,
output reg [15:0] misalign,
output reg ready);
reg [15:0] cnt;
reg cnt_en, cnt_reset;
reg vs_a_in_r, vs_b_in_r;
assign vs_a_rising = vs_a_in > vs_a_in_r;
assign vs_b_rising = vs_b_in > vs_b_in_r;
always @(posedge clk_in)
begin
vs_a_in_r <= vs_a_in;
vs_b_in_r <= vs_b_in;
end
always @(posedge clk_in)
if (reset)
begin
{ ready, cnt_en } <= 2'b00;
misalign <= 0;
end else begin
if ((vs_a_in == 1'b0) && (vs_b_in == 1'b0))
{ ready, cnt_reset } <= 2'b01;
else
cnt_reset <= 1'b0;
/* beginning */
if (vs_a_rising && vs_b_rising)
begin
misalign <= 0;
{ ready, cnt_en } <= 2'b10;
end
else if ((vs_a_rising > vs_b_in) || (vs_b_rising > vs_a_in))
{ ready, cnt_en } <= 2'b01;
/* ending */
if ((cnt_en == 1'b1) && (vs_a_rising || vs_b_rising))
begin
{ ready, cnt_en } <= 2'b10;
misalign <= vs_a_rising ? (-(cnt + 1)) : (cnt + 1);
end
end